4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2017 Peter Tribble.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/sysmacros.h>
45 #include <sys/types.h>
47 #include <sys/statvfs.h>
50 #include "pkglibmsgs.h"
51 #include "pkglocale.h"
54 extern char *devattr(char *device
, char *attribute
);
55 extern int pkgnmchk(register char *pkg
, register char *spec
,
57 extern int getvol(char *device
, char *label
, int options
, char *prompt
);
61 #define DDPROC "/usr/bin/dd"
62 #define CPIOPROC "/usr/bin/cpio"
66 #define G_TM_TAPE 1 /* Tapemaster controller */
67 #define G_XY_DISK 3 /* xy disks */
68 #define G_SD_DISK 7 /* scsi sd disk */
69 #define G_XT_TAPE 8 /* xt tapes */
70 #define G_SF_FLOPPY 9 /* sf floppy */
71 #define G_XD_DISK 10 /* xd disks */
72 #define G_ST_TAPE 11 /* scsi tape */
73 #define G_NS 12 /* noswap pseudo-dev */
74 #define G_RAM 13 /* ram pseudo-dev */
75 #define G_FT 14 /* tftp */
76 #define G_HD 15 /* 386 network disk */
77 #define G_FD 16 /* 386 AT disk */
78 #define G_FILE 28 /* file, not a device */
79 #define G_NO_DEV 29 /* device does not require special treatment */
80 #define G_DEV_MAX 30 /* last valid device type */
84 char pkg
[NON_ABI_NAMELNGTH
];
91 #define ds_nparts ds_toc->nparts
92 #define ds_maxsiz ds_toc->maxsiz
94 int ds_totread
; /* total number of parts read */
96 int ds_curpartcnt
= -1;
98 int ds_next(char *device
, char *instdir
);
99 int ds_ginit(char *device
);
100 int ds_close(int pkgendflg
);
103 static int ds_realfd
= -1; /* file descriptor for real device */
104 static int ds_read
; /* number of parts read for current package */
105 static int ds_volno
; /* volume number of current volume */
106 static int ds_volcnt
; /* total number of volumes */
107 static char ds_volnos
[128]; /* parts/volume info */
108 static char *ds_device
;
109 static int ds_volpart
; /* number of parts read in current volume, */
110 /* including skipped parts */
111 static int ds_bufsize
;
112 static int ds_skippart
; /* number of parts skipped in current volume */
114 static int ds_getnextvol(char *device
);
115 static int ds_skip(char *device
, int nskip
);
118 ds_order(char *list
[])
120 struct dstoc
*toc_pt
;
127 for (j
= n
; list
[j
]; j
++) {
128 if (strcmp(list
[j
], toc_pt
->pkg
) == 0) {
129 /* just swap places in the array */
135 toc_pt
= toc_pt
->next
;
139 static char *pds_header
;
140 static char *ds_header
;
141 static int ds_headsize
;
144 ds_gets(char *buf
, int size
)
149 nextp
= strchr(pds_header
, '\n');
151 length
= strlen(pds_header
);
154 if ((ds_header
= (char *)realloc(ds_header
,
155 ds_headsize
+ BLK_SIZE
)) == NULL
)
157 if (read(ds_fd
, ds_header
+ ds_headsize
, BLK_SIZE
) < BLK_SIZE
)
159 ds_headsize
+= BLK_SIZE
;
160 nextp
= strchr(pds_header
, '\n');
164 if (length
+ (int)strlen(pds_header
) > size
)
166 (void) strncpy(buf
+ length
, pds_header
, strlen(pds_header
));
167 buf
[length
+ strlen(pds_header
)] = '\0';
168 pds_header
= nextp
+ 1;
172 if ((int)strlen(pds_header
) > size
)
174 (void) strncpy(buf
, pds_header
, strlen(pds_header
));
175 buf
[strlen(pds_header
)] = '\0';
176 pds_header
= nextp
+ 1;
181 * function to determine if media is datastream or mounted
185 ds_readbuf(char *device
)
191 if ((ds_fd
= open(device
, O_RDONLY
)) >= 0 &&
192 read(ds_fd
, buf
, BLK_SIZE
) == BLK_SIZE
&&
193 strncmp(buf
, HDR_PREFIX
, 20) == 0) {
194 if ((ds_header
= (char *)calloc(BLK_SIZE
, 1)) == NULL
) {
195 progerr(pkg_gt(ERR_UNPACK
));
196 logerr(pkg_gt(MSG_MEM
));
200 (void) memcpy(ds_header
, buf
, BLK_SIZE
);
201 ds_headsize
= BLK_SIZE
;
203 if (ds_ginit(device
) < 0) {
204 progerr(pkg_gt(ERR_UNPACK
));
205 logerr(pkg_gt(MSG_OPEN
), device
, errno
);
210 } else if (ds_fd
>= 0) {
218 * Determine how many additional volumes are needed for current package.
219 * Note: a 0 will occur as first volume number when the package begins
220 * on the next volume.
223 ds_volsum(struct dstoc
*toc
)
225 int curpartcnt
, volcnt
;
226 char volnos
[128], tmpvol
[128];
227 if (toc
->volnos
[0]) {
229 (void) sscanf(toc
->volnos
, "%d %[ 0-9]", &curpartcnt
, volnos
);
232 while (sum
< toc
->nparts
&& sscanf(volnos
, "%d %[ 0-9]",
233 &index
, tmpvol
) >= 1) {
234 (void) strcpy(volnos
, tmpvol
);
238 /* side effect - set number of parts read on current volume */
242 ds_volpart
+= toc
->nparts
;
246 /* initialize ds_curpartcnt and ds_volnos */
250 if (ds_toc
->volnos
[0])
251 (void) sscanf(ds_toc
->volnos
, "%d %[ 0-9]", &ds_curpartcnt
,
258 * functions to pass current package info to exec'ed program
261 ds_putinfo(char *buf
, size_t sz
)
263 (void) snprintf(buf
, sz
, "%d %d %d %d %d %d %d %d %d %d %s",
264 ds_fd
, ds_realfd
, ds_volcnt
, ds_volno
, ds_totread
, ds_volpart
,
265 ds_skippart
, ds_bufsize
, ds_toc
->nparts
, ds_toc
->maxsiz
,
270 ds_getinfo(char *string
)
272 ds_toc
= (struct dstoc
*)calloc(1, sizeof (struct dstoc
));
273 (void) sscanf(string
, "%d %d %d %d %d %d %d %d %d %d %[ 0-9]",
274 &ds_fd
, &ds_realfd
, &ds_volcnt
, &ds_volno
, &ds_totread
,
275 &ds_volpart
, &ds_skippart
, &ds_bufsize
, &ds_toc
->nparts
,
276 &ds_toc
->maxsiz
, ds_toc
->volnos
);
278 return (ds_toc
->nparts
);
282 * Return true if the file descriptor (ds_fd) is open on the package stream.
287 return (ds_fd
>= 0 ? B_TRUE
: B_FALSE
);
291 * Read the source device. Acquire the header data and check it for validity.
294 ds_init(char *device
, char **pkg
, char *norewind
)
296 struct dstoc
*tail
, *toc_pt
;
300 int i
, n
, count
= 0, header_size
= BLK_SIZE
;
302 if (!ds_header
) { /* If the header hasn't been read yet */
306 /* always start with rewind device */
307 if ((ds_fd
= open(device
, O_RDONLY
)) < 0) {
308 progerr(pkg_gt(ERR_UNPACK
));
309 logerr(pkg_gt(MSG_OPEN
), device
, errno
);
313 /* allocate room for the header equivalent to a block */
314 if ((ds_header
= (char *)calloc(BLK_SIZE
, 1)) == NULL
) {
315 progerr(pkg_gt(ERR_UNPACK
));
316 logerr(pkg_gt(MSG_MEM
));
320 /* initialize the device */
321 if (ds_ginit(device
) < 0) {
323 progerr(pkg_gt(ERR_UNPACK
));
324 logerr(pkg_gt(MSG_OPEN
), device
, errno
);
328 /* read a logical block from the source device */
329 if (read(ds_fd
, ds_header
, BLK_SIZE
) != BLK_SIZE
) {
331 progerr(pkg_gt(ERR_UNPACK
));
332 logerr(pkg_gt(MSG_TOC
));
338 * This loop scans the medium for the start of the header.
339 * If the above read worked, we skip this. If it did't, this
340 * loop will retry the read ten times looking for the header
343 while (strncmp(ds_header
, HDR_PREFIX
, 20) != 0) {
344 /* only ten tries iff the device rewinds */
345 if (!norewind
|| count
++ > 10) {
346 progerr(pkg_gt(ERR_UNPACK
));
347 logerr(pkg_gt(MSG_TOC
));
352 /* read through to the last block */
354 while (read(ds_fd
, ds_header
, BLK_SIZE
) > 0)
357 /* then close the device */
361 if ((ds_fd
= open(norewind
, O_RDONLY
)) < 0) {
362 progerr(pkg_gt(ERR_UNPACK
));
363 logerr(pkg_gt(MSG_OPEN
), device
, errno
);
364 (void) free(ds_header
);
368 /* initialize the device */
369 if (ds_ginit(device
) < 0) {
371 progerr(pkg_gt(ERR_UNPACK
));
372 logerr(pkg_gt(MSG_OPEN
), device
, errno
);
376 /* read the block again */
377 if (read(ds_fd
, ds_header
, BLK_SIZE
) != BLK_SIZE
) {
379 progerr(pkg_gt(ERR_UNPACK
));
380 logerr(pkg_gt(MSG_TOC
));
386 /* Now keep scanning until the whole header is in place. */
387 while (strstr(ds_header
, HDR_SUFFIX
) == NULL
) {
388 /* We need a bigger buffer */
389 if ((ds_header
= (char *)realloc(ds_header
,
390 header_size
+ BLK_SIZE
)) == NULL
) {
391 progerr(pkg_gt(ERR_UNPACK
));
392 logerr(pkg_gt(MSG_MEM
));
397 /* clear the new memory */
398 (void) memset(ds_header
+ header_size
, '\0',
402 /* read a logical block from the source device */
403 if (read(ds_fd
, ds_header
+ header_size
, BLK_SIZE
) !=
406 progerr(pkg_gt(ERR_UNPACK
));
407 logerr(pkg_gt(MSG_TOC
));
411 header_size
+= BLK_SIZE
; /* new size */
415 * remember rewind device for ds_close to rewind at
420 ds_headsize
= header_size
;
424 pds_header
= ds_header
;
426 /* read datastream table of contents */
427 ds_head
= tail
= (struct dstoc
*)0;
430 while (ret
= ds_gets(line
, LSIZE
)) {
431 if (strcmp(line
, HDR_SUFFIX
) == 0)
433 if (!line
[0] || line
[0] == '#')
435 toc_pt
= (struct dstoc
*)calloc(1, sizeof (struct dstoc
));
437 progerr(pkg_gt(ERR_UNPACK
));
438 logerr(pkg_gt(MSG_MEM
));
440 (void) free(ds_header
);
443 /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */
444 if (sscanf(line
, "%s %d %d %[ 0-9]", toc_pt
->pkg
,
445 &toc_pt
->nparts
, &toc_pt
->maxsiz
, toc_pt
->volnos
) < 3) {
446 progerr(pkg_gt(ERR_UNPACK
));
447 logerr(pkg_gt(MSG_TOC
));
449 (void) free(ds_header
);
457 ds_head
= tail
= toc_pt
;
458 ds_volcnt
+= ds_volsum(toc_pt
);
461 progerr(pkg_gt(ERR_UNPACK
));
462 logerr(pkg_gt(MSG_TOC
));
463 (void) free(ds_header
);
466 (void) sighold(SIGINT
);
467 (void) sigrelse(SIGINT
);
469 progerr(pkg_gt(ERR_UNPACK
));
470 logerr(pkg_gt(MSG_EMPTY
));
471 (void) free(ds_header
);
474 /* this could break, thanks to cpio command limit */
475 (void) snprintf(cmd
, sizeof (cmd
), "%s -icdumD -C %d",
476 CPIOPROC
, (int)BLK_SIZE
);
478 for (i
= 0; pkg
[i
]; i
++) {
479 if (strcmp(pkg
[i
], "all") == 0)
482 (void) strlcat(cmd
, " ", CMDSIZ
);
485 (void) strlcat(cmd
, pkg
[i
], CMDSIZ
);
486 (void) strlcat(cmd
, "'/*' ", CMDSIZ
);
487 (void) strlcat(cmd
, " ", CMDSIZ
);
490 if (n
= esystem(cmd
, ds_fd
, -1)) {
492 progerr(pkg_gt(ERR_UNPACK
));
493 logerr(pkg_gt(MSG_CMDFAIL
), cmd
, n
);
494 (void) free(ds_header
);
505 ds_findpkg(char *device
, char *pkg
)
508 int nskip
, ods_volpart
;
510 if (ds_head
== NULL
) {
513 if (ds_init(device
, pkglist
, NULL
))
517 if (!pkg
|| pkgnmchk(pkg
, "all", 0)) {
518 progerr(pkg_gt(ERR_UNPACK
));
519 logerr(pkg_gt(MSG_PKGNAME
));
528 if (strcmp(ds_toc
->pkg
, pkg
) == 0)
530 nskip
+= ds_toc
->nparts
;
531 ds_volno
+= ds_volsum(ds_toc
);
532 ds_toc
= ds_toc
->next
;
535 progerr(pkg_gt(ERR_UNPACK
));
536 logerr(pkg_gt(MSG_NOPKG
), pkg
);
542 if (ds_curpartcnt
> 0) {
543 ods_volpart
= ds_volpart
;
545 * skip past archives belonging to last package on current
548 if (ds_volpart
> 0 && ds_getnextvol(device
))
550 ds_totread
= nskip
- ods_volpart
;
551 if (ds_skip(device
, ods_volpart
))
553 } else if (ds_curpartcnt
< 0) {
554 if (ds_skip(device
, nskip
- ds_totread
))
563 * Get datastream part
564 * Call for first part should be preceded by
569 ds_getpkg(char *device
, int n
, char *dstdir
)
571 struct statvfs64 svfsb
;
572 u_longlong_t free_blocks
;
574 if (ds_read
>= ds_nparts
)
579 else if ((ds_read
> n
) || (n
> ds_nparts
))
583 if (statvfs64(".", &svfsb
)) {
584 progerr(pkg_gt(ERR_UNPACK
));
585 logerr(pkg_gt(MSG_STATFS
), errno
);
588 free_blocks
= (((long)svfsb
.f_frsize
> 0) ?
589 howmany(svfsb
.f_frsize
, DEV_BSIZE
) :
590 howmany(svfsb
.f_bsize
, DEV_BSIZE
)) * svfsb
.f_bfree
;
591 if ((ds_maxsiz
+ 50) > free_blocks
) {
592 progerr(pkg_gt(ERR_UNPACK
));
593 logerr(pkg_gt(MSG_NOSPACE
), ds_maxsiz
+50, free_blocks
);
597 return (ds_next(device
, dstdir
));
601 ds_getnextvol(char *device
)
608 (void) sprintf(prompt
,
609 pkg_gt("Insert %%v %d of %d into %%p"),
610 ds_volno
, ds_volcnt
);
611 if (n
= getvol(device
, NULL
, NULL
, prompt
))
613 if ((ds_fd
= open(device
, O_RDONLY
)) < 0)
615 if (ds_ginit(device
) < 0) {
624 * called by ds_findpkg to skip past archives for unwanted packages
628 ds_skip(char *device
, int nskip
)
631 int n
, onskip
= nskip
;
635 (void) snprintf(cmd
, sizeof (cmd
),
636 "%s -ictD -C %d > /dev/null", CPIOPROC
, (int)BLK_SIZE
);
637 if (n
= esystem(cmd
, ds_fd
, -1)) {
639 progerr(pkg_gt(ERR_UNPACK
));
640 logerr(pkg_gt(MSG_CMDFAIL
), cmd
, n
);
642 if (ds_volno
== 1 || ds_volpart
> 0)
644 if (n
= ds_getnextvol(device
))
648 ds_totread
+= onskip
;
650 ds_skippart
= onskip
;
654 /* skip to end of package if necessary */
656 ds_skiptoend(char *device
)
658 if (ds_read
< ds_nparts
&& ds_curpartcnt
< 0)
659 (void) ds_skip(device
, ds_nparts
- ds_read
);
663 ds_next(char *device
, char *instdir
)
665 char cmd
[CMDSIZ
], tmpvol
[128];
666 int nparts
, n
, index
;
670 if (ds_read
+ 1 > ds_curpartcnt
&& ds_curpartcnt
>= 0) {
672 if (n
= ds_getnextvol(device
))
674 (void) sscanf(ds_volnos
, "%d %[ 0-9]", &index
, tmpvol
);
675 (void) strcpy(ds_volnos
, tmpvol
);
676 ds_curpartcnt
+= index
;
678 (void) snprintf(cmd
, sizeof (cmd
), "%s -icdumD -C %d",
679 CPIOPROC
, (int)BLK_SIZE
);
680 if (n
= esystem(cmd
, ds_fd
, -1)) {
682 progerr(pkg_gt(ERR_UNPACK
));
683 logerr(pkg_gt(MSG_CMDFAIL
), cmd
, n
);
688 nparts
= ds_toc
->nparts
;
689 if (n
|| (n
= ckvolseq(instdir
, ds_read
+ 1, nparts
))) {
690 if (ds_volno
== 1 || ds_volpart
> ds_skippart
)
693 if (n
= ds_getnextvol(device
))
707 * ds_ginit: Determine the device being accessed, set the buffer size,
708 * and perform any device specific initialization.
712 ds_ginit(char *device
)
715 char *pbufsize
, cmd
[CMDSIZ
];
718 if ((pbufsize
= devattr(device
, "bufsize")) != NULL
) {
719 ds_bufsize
= atoi(pbufsize
);
720 (void) free(pbufsize
);
722 ds_bufsize
= BLK_SIZE
;
723 oflag
= fcntl(ds_fd
, F_GETFL
, 0);
725 if (ds_bufsize
> BLK_SIZE
) {
726 if (oflag
& O_WRONLY
)
730 fd2
= fcntl(fd
, F_DUPFD
, fd
);
732 (void) fcntl(ds_fd
, F_DUPFD
, fd
);
734 (void) snprintf(cmd
, sizeof (cmd
),
735 "%s obs=%d 2>/dev/null", DDPROC
, ds_bufsize
);
737 (void) snprintf(cmd
, sizeof (cmd
),
738 "%s ibs=%d 2>/dev/null", DDPROC
, ds_bufsize
);
739 if ((ds_pp
= popen(cmd
, fd
? "w" : "r")) == NULL
) {
740 progerr(pkg_gt(ERR_TRANSFER
));
741 logerr(pkg_gt(MSG_POPEN
), cmd
, errno
);
745 (void) fcntl(fd2
, F_DUPFD
, fd
);
748 ds_fd
= fileno(ds_pp
);
754 ds_close(int pkgendflg
)
760 (void) free(ds_header
);
761 ds_header
= (char *)NULL
;
766 (void) pclose(ds_pp
);
768 (void) close(ds_realfd
);
771 } else if (ds_fd
>= 0) {
778 if ((n
= open(ds_device
, 0)) >= 0)