xref: /illumos-gate/usr/src/lib/libpkg/common/dstream.c (revision 1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 
30 
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/sysmacros.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/statvfs.h>
44 #include <fcntl.h>
45 #include <openssl/err.h>
46 #include "pkglib.h"
47 #include "pkglibmsgs.h"
48 #include "pkglocale.h"
49 
50 /* libadm.a */
51 extern char	*devattr(char *device, char *attribute);
52 extern int	pkgnmchk(register char *pkg, register char *spec,
53 				int presvr4flg);
54 extern int	getvol(char *device, char *label, int options, char *prompt);
55 
56 #define	CMDSIZ	512
57 #define	LSIZE	128
58 #define	DDPROC		"/usr/bin/dd"
59 #define	CPIOPROC	"/usr/bin/cpio"
60 
61 /* device types */
62 
63 #define	G_TM_TAPE	1   /* Tapemaster controller */
64 #define	G_XY_DISK	3   /* xy disks */
65 #define	G_SD_DISK	7   /* scsi sd disk */
66 #define	G_XT_TAPE	8   /* xt tapes */
67 #define	G_SF_FLOPPY	9   /* sf floppy */
68 #define	G_XD_DISK	10  /* xd disks */
69 #define	G_ST_TAPE	11  /* scsi tape */
70 #define	G_NS		12  /* noswap pseudo-dev */
71 #define	G_RAM		13  /* ram pseudo-dev */
72 #define	G_FT		14  /* tftp */
73 #define	G_HD		15  /* 386 network disk */
74 #define	G_FD		16  /* 386 AT disk */
75 #define	G_FILE		28  /* file, not a device */
76 #define	G_NO_DEV	29  /* device does not require special treatment */
77 #define	G_DEV_MAX	30  /* last valid device type */
78 
79 struct dstoc {
80 	int	cnt;
81 	char	pkg[NON_ABI_NAMELNGTH];
82 	int	nparts;
83 	long	maxsiz;
84 	char    volnos[128];
85 	struct dstoc *next;
86 } *ds_head, *ds_toc;
87 
88 #define	ds_nparts	ds_toc->nparts
89 #define	ds_maxsiz	ds_toc->maxsiz
90 
91 int	ds_totread; 	/* total number of parts read */
92 int	ds_fd = -1;
93 int	ds_curpartcnt = -1;
94 
95 int	ds_next(char *device, char *instdir);
96 int	ds_ginit(char *device);
97 int	ds_close(int pkgendflg);
98 
99 static FILE	*ds_pp;
100 static int	ds_realfd = -1; 	/* file descriptor for real device */
101 static int	ds_read; 	/* number of parts read for current package */
102 static int	ds_volno; 	/* volume number of current volume */
103 static int	ds_volcnt; 	/* total number of volumes */
104 static char	ds_volnos[128]; 	/* parts/volume info */
105 static char	*ds_device;
106 static int	ds_volpart;	/* number of parts read in current volume, */
107 						/* including skipped parts */
108 static int	ds_bufsize;
109 static int	ds_skippart; 	/* number of parts skipped in current volume */
110 
111 static int	ds_getnextvol(char *device);
112 static int	ds_skip(char *device, int nskip);
113 
114 void
115 ds_order(char *list[])
116 {
117 	struct dstoc *toc_pt;
118 	register int j, n;
119 	char	*pt;
120 
121 	toc_pt = ds_head;
122 	n = 0;
123 	while (toc_pt) {
124 		for (j = n; list[j]; j++) {
125 			if (strcmp(list[j], toc_pt->pkg) == 0) {
126 				/* just swap places in the array */
127 				pt = list[n];
128 				list[n++] = list[j];
129 				list[j] = pt;
130 			}
131 		}
132 		toc_pt = toc_pt->next;
133 	}
134 }
135 
136 static char *pds_header;
137 static char *ds_header;
138 static char *ds_header_raw;
139 static int ds_headsize;
140 
141 static char *
142 ds_gets(char *buf, int size)
143 {
144 	int length;
145 	char *nextp;
146 
147 	nextp = strchr(pds_header, '\n');
148 	if (nextp == NULL) {
149 		length = strlen(pds_header);
150 		if (length > size)
151 			return (0);
152 		if ((ds_header = (char *)realloc(ds_header,
153 		    ds_headsize + BLK_SIZE)) == NULL)
154 			return (0);
155 		if (read(ds_fd, ds_header + ds_headsize, BLK_SIZE) < BLK_SIZE)
156 			return (0);
157 		ds_headsize += BLK_SIZE;
158 		nextp = strchr(pds_header, '\n');
159 		if (nextp == NULL)
160 			return (0);
161 		*nextp = '\0';
162 		if (length + (int)strlen(pds_header) > size)
163 			return (0);
164 		(void) strncpy(buf + length, pds_header, strlen(pds_header));
165 		buf[length + strlen(pds_header)] = '\0';
166 		pds_header = nextp + 1;
167 		return (buf);
168 	}
169 	*nextp = '\0';
170 	if ((int)strlen(pds_header) > size)
171 		return (0);
172 	(void) strncpy(buf, pds_header, strlen(pds_header));
173 	buf[strlen(pds_header)] = '\0';
174 	pds_header = nextp + 1;
175 	return (buf);
176 }
177 
178 /*
179  * function to determine if media is datastream or mounted
180  * floppy
181  */
182 int
183 ds_readbuf(char *device)
184 {
185 	char buf[BLK_SIZE];
186 
187 	if (ds_fd >= 0)
188 		(void) close(ds_fd);
189 	if ((ds_fd = open(device, O_RDONLY)) >= 0 &&
190 	    read(ds_fd, buf, BLK_SIZE) == BLK_SIZE &&
191 	    strncmp(buf, HDR_PREFIX, 20) == 0) {
192 		if ((ds_header = (char *)calloc(BLK_SIZE, 1)) == NULL) {
193 			progerr(pkg_gt(ERR_UNPACK));
194 			logerr(pkg_gt(MSG_MEM));
195 			(void) ds_close(0);
196 			return (0);
197 		}
198 		(void) memcpy(ds_header, buf, BLK_SIZE);
199 		ds_headsize = BLK_SIZE;
200 
201 		if (ds_ginit(device) < 0) {
202 			progerr(pkg_gt(ERR_UNPACK));
203 			logerr(pkg_gt(MSG_OPEN), device, errno);
204 			(void) ds_close(0);
205 			return (0);
206 		}
207 		return (1);
208 	} else if (ds_fd >= 0) {
209 		(void) close(ds_fd);
210 		ds_fd = -1;
211 	}
212 	return (0);
213 }
214 
215 /*
216  * Determine how many additional volumes are needed for current package.
217  * Note: a 0 will occur as first volume number when the package begins
218  * on the next volume.
219  */
220 static int
221 ds_volsum(struct dstoc *toc)
222 {
223 	int curpartcnt, volcnt;
224 	char volnos[128], tmpvol[128];
225 	if (toc->volnos[0]) {
226 		int index, sum;
227 		(void) sscanf(toc->volnos, "%d %[ 0-9]", &curpartcnt, volnos);
228 		volcnt = 0;
229 		sum = curpartcnt;
230 		while (sum < toc->nparts && sscanf(volnos, "%d %[ 0-9]",
231 		    &index, tmpvol) >= 1) {
232 			(void) strcpy(volnos, tmpvol);
233 			volcnt++;
234 			sum += index;
235 		}
236 		/* side effect - set number of parts read on current volume */
237 		ds_volpart = index;
238 		return (volcnt);
239 	}
240 	ds_volpart += toc->nparts;
241 	return (0);
242 }
243 
244 /* initialize ds_curpartcnt and ds_volnos */
245 static void
246 ds_pkginit(void)
247 {
248 	if (ds_toc->volnos[0])
249 		(void) sscanf(ds_toc->volnos, "%d %[ 0-9]", &ds_curpartcnt,
250 		    ds_volnos);
251 	else
252 		ds_curpartcnt = -1;
253 }
254 
255 /*
256  * functions to pass current package info to exec'ed program
257  */
258 void
259 ds_putinfo(char *buf, size_t sz)
260 {
261 	(void) snprintf(buf, sz, "%d %d %d %d %d %d %d %d %d %d %s",
262 	    ds_fd, ds_realfd, ds_volcnt, ds_volno, ds_totread, ds_volpart,
263 	    ds_skippart, ds_bufsize, ds_toc->nparts, ds_toc->maxsiz,
264 	    ds_toc->volnos);
265 }
266 
267 int
268 ds_getinfo(char *string)
269 {
270 	ds_toc = (struct dstoc *)calloc(1, sizeof (struct dstoc));
271 	(void) sscanf(string, "%d %d %d %d %d %d %d %d %d %d %[ 0-9]",
272 	    &ds_fd, &ds_realfd, &ds_volcnt, &ds_volno, &ds_totread,
273 	    &ds_volpart, &ds_skippart, &ds_bufsize, &ds_toc->nparts,
274 	    &ds_toc->maxsiz, ds_toc->volnos);
275 	ds_pkginit();
276 	return (ds_toc->nparts);
277 }
278 
279 /*
280  * Return true if the file descriptor (ds_fd) is open on the package stream.
281  */
282 boolean_t
283 ds_fd_open(void)
284 {
285 	return (ds_fd >= 0 ? B_TRUE : B_FALSE);
286 }
287 
288 /*
289  * Read the source device. Acquire the header data and check it for validity.
290  */
291 int
292 ds_init(char *device, char **pkg, char *norewind)
293 {
294 	struct dstoc *tail, *toc_pt;
295 	char	*ret;
296 	char	cmd[CMDSIZ];
297 	char	line[LSIZE+1];
298 	int	i, n, count = 0, header_size = BLK_SIZE;
299 
300 	if (!ds_header) { 	/* If the header hasn't been read yet */
301 		if (ds_fd >= 0)
302 			(void) ds_close(0);
303 
304 		/* always start with rewind device */
305 		if ((ds_fd = open(device, O_RDONLY)) < 0) {
306 			progerr(pkg_gt(ERR_UNPACK));
307 			logerr(pkg_gt(MSG_OPEN), device, errno);
308 			return (-1);
309 		}
310 
311 		/* allocate room for the header equivalent to a block */
312 		if ((ds_header = (char *)calloc(BLK_SIZE, 1)) == NULL) {
313 			progerr(pkg_gt(ERR_UNPACK));
314 			logerr(pkg_gt(MSG_MEM));
315 			return (-1);
316 		}
317 
318 		/* initialize the device */
319 		if (ds_ginit(device) < 0) {
320 			(void) ds_close(0);
321 			progerr(pkg_gt(ERR_UNPACK));
322 			logerr(pkg_gt(MSG_OPEN), device, errno);
323 			return (-1);
324 		}
325 
326 		/* read a logical block from the source device */
327 		if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) {
328 			rpterr();
329 			progerr(pkg_gt(ERR_UNPACK));
330 			logerr(pkg_gt(MSG_TOC));
331 			(void) ds_close(0);
332 			return (-1);
333 		}
334 
335 		/*
336 		 * This loop scans the medium for the start of the header.
337 		 * If the above read worked, we skip this. If it did't, this
338 		 * loop will retry the read ten times looking for the header
339 		 * marker string.
340 		 */
341 		while (strncmp(ds_header, HDR_PREFIX, 20) != 0) {
342 			/* only ten tries iff the device rewinds */
343 			if (!norewind || count++ > 10) {
344 				progerr(pkg_gt(ERR_UNPACK));
345 				logerr(pkg_gt(MSG_TOC));
346 				(void) ds_close(0);
347 				return (-1);
348 			}
349 
350 			/* read through to the last block */
351 			if (count > 1)
352 				while (read(ds_fd, ds_header, BLK_SIZE) > 0)
353 					;
354 
355 			/* then close the device */
356 			(void) ds_close(0);
357 
358 			/* and reopen it */
359 			if ((ds_fd = open(norewind, O_RDONLY)) < 0) {
360 				progerr(pkg_gt(ERR_UNPACK));
361 				logerr(pkg_gt(MSG_OPEN), device, errno);
362 				(void) free(ds_header);
363 				return (-1);
364 			}
365 
366 			/* initialize the device */
367 			if (ds_ginit(device) < 0) {
368 				(void) ds_close(0);
369 				progerr(pkg_gt(ERR_UNPACK));
370 				logerr(pkg_gt(MSG_OPEN), device, errno);
371 				return (-1);
372 			}
373 
374 			/* read the block again */
375 			if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) {
376 				rpterr();
377 				progerr(pkg_gt(ERR_UNPACK));
378 				logerr(pkg_gt(MSG_TOC));
379 				(void) ds_close(0);
380 				return (-1);
381 			}
382 		}
383 
384 		/* Now keep scanning until the whole header is in place. */
385 		while (strstr(ds_header, HDR_SUFFIX) == NULL) {
386 			/* We need a bigger buffer */
387 			if ((ds_header = (char *)realloc(ds_header,
388 			    header_size + BLK_SIZE)) == NULL) {
389 				progerr(pkg_gt(ERR_UNPACK));
390 				logerr(pkg_gt(MSG_MEM));
391 				(void) ds_close(0);
392 				return (1);
393 			}
394 
395 			/* clear the new memory */
396 			(void) memset(ds_header + header_size, '\0',
397 			    BLK_SIZE);
398 
399 
400 			/* read a logical block from the source device */
401 			if (read(ds_fd, ds_header + header_size, BLK_SIZE) !=
402 			    BLK_SIZE) {
403 				rpterr();
404 				progerr(pkg_gt(ERR_UNPACK));
405 				logerr(pkg_gt(MSG_TOC));
406 				(void) ds_close(0);
407 				return (-1);
408 			} else
409 				header_size += BLK_SIZE;	/* new size */
410 		}
411 
412 		/*
413 		 * remember rewind device for ds_close to rewind at
414 		 * close
415 		 */
416 		if (count >= 1)
417 			ds_device = device;
418 		ds_headsize = header_size;
419 
420 	}
421 
422 	pds_header = ds_header;
423 
424 	/* save raw copy of header for later use in BIO_dump_header */
425 	if ((ds_header_raw = (char *)malloc(header_size)) == NULL) {
426 		progerr(pkg_gt(ERR_UNPACK));
427 		logerr(pkg_gt(MSG_MEM));
428 		(void) ds_close(0);
429 		return (1);
430 	}
431 	(void) memcpy(ds_header_raw, ds_header, header_size);
432 
433 	/* read datastream table of contents */
434 	ds_head = tail = (struct dstoc *)0;
435 	ds_volcnt = 1;
436 
437 	while (ret = ds_gets(line, LSIZE)) {
438 		if (strcmp(line, HDR_SUFFIX) == 0)
439 			break;
440 		if (!line[0] || line[0] == '#')
441 			continue;
442 		toc_pt = (struct dstoc *)calloc(1, sizeof (struct dstoc));
443 		if (!toc_pt) {
444 			progerr(pkg_gt(ERR_UNPACK));
445 			logerr(pkg_gt(MSG_MEM));
446 			ecleanup();
447 			(void) free(ds_header);
448 			return (-1);
449 		}
450 		/* LINTED E_SEC_SCANF_UNBOUNDED_COPY */
451 		if (sscanf(line, "%s %d %d %[ 0-9]", toc_pt->pkg,
452 		    &toc_pt->nparts, &toc_pt->maxsiz, toc_pt->volnos) < 3) {
453 			progerr(pkg_gt(ERR_UNPACK));
454 			logerr(pkg_gt(MSG_TOC));
455 			free(toc_pt);
456 			(void) free(ds_header);
457 			ecleanup();
458 			return (-1);
459 		}
460 		if (tail) {
461 			tail->next = toc_pt;
462 			tail = toc_pt;
463 		} else
464 			ds_head = tail = toc_pt;
465 		ds_volcnt += ds_volsum(toc_pt);
466 	}
467 	if (!ret) {
468 		progerr(pkg_gt(ERR_UNPACK));
469 		logerr(pkg_gt(MSG_TOC));
470 		(void) free(ds_header);
471 		return (-1);
472 	}
473 	(void) sighold(SIGINT);
474 	(void) sigrelse(SIGINT);
475 	if (!ds_head) {
476 		progerr(pkg_gt(ERR_UNPACK));
477 		logerr(pkg_gt(MSG_EMPTY));
478 		(void) free(ds_header);
479 		return (-1);
480 	}
481 	/* this could break, thanks to cpio command limit */
482 	(void) snprintf(cmd, sizeof (cmd), "%s -icdumD -C %d",
483 	    CPIOPROC, (int)BLK_SIZE);
484 	n = 0;
485 	for (i = 0; pkg[i]; i++) {
486 		if (strcmp(pkg[i], "all") == 0)
487 			continue;
488 		if (n == 0) {
489 			(void) strlcat(cmd, " ", CMDSIZ);
490 			n = 1;
491 		}
492 		(void) strlcat(cmd, pkg[i], CMDSIZ);
493 		(void) strlcat(cmd, "'/*' ", CMDSIZ);
494 
495 		/* extract signature too, if present. */
496 		(void) strlcat(cmd, SIGNATURE_FILENAME, CMDSIZ);
497 		(void) strlcat(cmd, " ", CMDSIZ);
498 	}
499 
500 	/*
501 	 * if we are extracting all packages (pkgs == NULL),
502 	 * signature will automatically be extracted
503 	 */
504 	if (n = esystem(cmd, ds_fd, -1)) {
505 		rpterr();
506 		progerr(pkg_gt(ERR_UNPACK));
507 		logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
508 		(void) free(ds_header);
509 		return (-1);
510 	}
511 
512 	ds_toc = ds_head;
513 	ds_totread = 0;
514 	ds_volno = 1;
515 	return (0);
516 }
517 
518 int
519 ds_findpkg(char *device, char *pkg)
520 {
521 	char	*pkglist[2];
522 	int	nskip, ods_volpart;
523 
524 	if (ds_head == NULL) {
525 		pkglist[0] = pkg;
526 		pkglist[1] = NULL;
527 		if (ds_init(device, pkglist, NULL))
528 			return (-1);
529 	}
530 
531 	if (!pkg || pkgnmchk(pkg, "all", 0)) {
532 		progerr(pkg_gt(ERR_UNPACK));
533 		logerr(pkg_gt(MSG_PKGNAME));
534 		return (-1);
535 	}
536 
537 	nskip = 0;
538 	ds_volno = 1;
539 	ds_volpart = 0;
540 	ds_toc = ds_head;
541 	while (ds_toc) {
542 		if (strcmp(ds_toc->pkg, pkg) == 0)
543 			break;
544 		nskip += ds_toc->nparts;
545 		ds_volno += ds_volsum(ds_toc);
546 		ds_toc = ds_toc->next;
547 	}
548 	if (!ds_toc) {
549 		progerr(pkg_gt(ERR_UNPACK));
550 		logerr(pkg_gt(MSG_NOPKG), pkg);
551 		return (-1);
552 	}
553 
554 	ds_pkginit();
555 	ds_skippart = 0;
556 	if (ds_curpartcnt > 0) {
557 		ods_volpart = ds_volpart;
558 		/*
559 		 * skip past archives belonging to last package on current
560 		 * volume
561 		 */
562 		if (ds_volpart > 0 && ds_getnextvol(device))
563 			return (-1);
564 		ds_totread = nskip - ods_volpart;
565 		if (ds_skip(device, ods_volpart))
566 			return (-1);
567 	} else if (ds_curpartcnt < 0) {
568 		if (ds_skip(device, nskip - ds_totread))
569 			return (-1);
570 	} else
571 		ds_totread = nskip;
572 	ds_read = 0;
573 	return (ds_nparts);
574 }
575 
576 /*
577  * Get datastream part
578  * Call for first part should be preceded by
579  * call to ds_findpkg
580  */
581 
582 int
583 ds_getpkg(char *device, int n, char *dstdir)
584 {
585 	struct statvfs64 svfsb;
586 	u_longlong_t free_blocks;
587 
588 	if (ds_read >= ds_nparts)
589 		return (2);
590 
591 	if (ds_read == n)
592 		return (0);
593 	else if ((ds_read > n) || (n > ds_nparts))
594 		return (2);
595 
596 	if (ds_maxsiz > 0) {
597 		if (statvfs64(".", &svfsb)) {
598 			progerr(pkg_gt(ERR_UNPACK));
599 			logerr(pkg_gt(MSG_STATFS), errno);
600 			return (-1);
601 		}
602 		free_blocks = (((long)svfsb.f_frsize > 0) ?
603 		    howmany(svfsb.f_frsize, DEV_BSIZE) :
604 		    howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
605 		if ((ds_maxsiz + 50) > free_blocks) {
606 			progerr(pkg_gt(ERR_UNPACK));
607 			logerr(pkg_gt(MSG_NOSPACE), ds_maxsiz+50, free_blocks);
608 			return (-1);
609 		}
610 	}
611 	return (ds_next(device, dstdir));
612 }
613 
614 static int
615 ds_getnextvol(char *device)
616 {
617 	char prompt[128];
618 	int n;
619 
620 	if (ds_close(0))
621 		return (-1);
622 	(void) sprintf(prompt,
623 	    pkg_gt("Insert %%v %d of %d into %%p"),
624 	    ds_volno, ds_volcnt);
625 	if (n = getvol(device, NULL, NULL, prompt))
626 		return (n);
627 	if ((ds_fd = open(device, O_RDONLY)) < 0)
628 		return (-1);
629 	if (ds_ginit(device) < 0) {
630 		(void) ds_close(0);
631 		return (-1);
632 	}
633 	ds_volpart = 0;
634 	return (0);
635 }
636 
637 /*
638  * called by ds_findpkg to skip past archives for unwanted packages
639  * in current volume
640  */
641 static int
642 ds_skip(char *device, int nskip)
643 {
644 	char	cmd[CMDSIZ];
645 	int	n, onskip = nskip;
646 
647 	while (nskip--) {
648 		/* skip this one */
649 		(void) snprintf(cmd, sizeof (cmd),
650 		    "%s -ictD -C %d > /dev/null", CPIOPROC, (int)BLK_SIZE);
651 		if (n = esystem(cmd, ds_fd, -1)) {
652 			rpterr();
653 			progerr(pkg_gt(ERR_UNPACK));
654 			logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
655 			nskip = onskip;
656 			if (ds_volno == 1 || ds_volpart > 0)
657 				return (n);
658 			if (n = ds_getnextvol(device))
659 				return (n);
660 		}
661 	}
662 	ds_totread += onskip;
663 	ds_volpart = onskip;
664 	ds_skippart = onskip;
665 	return (0);
666 }
667 
668 /* skip to end of package if necessary */
669 void
670 ds_skiptoend(char *device)
671 {
672 	if (ds_read < ds_nparts && ds_curpartcnt < 0)
673 		(void) ds_skip(device, ds_nparts - ds_read);
674 }
675 
676 int
677 ds_next(char *device, char *instdir)
678 {
679 	char	cmd[CMDSIZ], tmpvol[128];
680 	int	nparts, n, index;
681 
682 	/*CONSTCOND*/
683 	while (1) {
684 		if (ds_read + 1 > ds_curpartcnt && ds_curpartcnt >= 0) {
685 			ds_volno++;
686 			if (n = ds_getnextvol(device))
687 				return (n);
688 			(void) sscanf(ds_volnos, "%d %[ 0-9]", &index, tmpvol);
689 			(void) strcpy(ds_volnos, tmpvol);
690 			ds_curpartcnt += index;
691 		}
692 		(void) snprintf(cmd, sizeof (cmd), "%s -icdumD -C %d",
693 		    CPIOPROC, (int)BLK_SIZE);
694 		if (n = esystem(cmd, ds_fd, -1)) {
695 			rpterr();
696 			progerr(pkg_gt(ERR_UNPACK));
697 			logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
698 		}
699 		if (ds_read == 0)
700 			nparts = 0;
701 		else
702 			nparts = ds_toc->nparts;
703 		if (n || (n = ckvolseq(instdir, ds_read + 1, nparts))) {
704 			if (ds_volno == 1 || ds_volpart > ds_skippart)
705 				return (-1);
706 
707 			if (n = ds_getnextvol(device))
708 				return (n);
709 			continue;
710 		}
711 		ds_read++;
712 		ds_totread++;
713 		ds_volpart++;
714 
715 		return (0);
716 	}
717 	/*NOTREACHED*/
718 }
719 
720 /*
721  * Name:		BIO_ds_dump
722  * Description:	Dumps all data from the static 'ds_fd' file handle into
723  *		the supplied BIO.
724  *
725  * Arguments:	err - where to record any errors.
726  *		device - Description of device being dumped into,
727  *			for error reporting
728  *		bio - BIO object to dump data into
729  *
730  * Returns :	zero - successfully dumped all data to EOF
731  *		non-zero - some failure occurred.
732  */
733 int
734 BIO_ds_dump(PKG_ERR *err, char *device, BIO *bio)
735 {
736 	int	amtread;
737 	char	readbuf[BLK_SIZE];
738 
739 	/*
740 	 * note this will read to the end of the device, so it won't
741 	 * work for character devices since we don't know when the
742 	 * end of the CPIO archive is
743 	 */
744 	while ((amtread = read(ds_fd, readbuf, BLK_SIZE)) != 0) {
745 		if (BIO_write(bio, readbuf, amtread) != amtread) {
746 			pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, device,
747 			    ERR_error_string(ERR_get_error(), NULL));
748 			return (1);
749 		}
750 	}
751 
752 	return (0);
753 	/*NOTREACHED*/
754 }
755 
756 
757 /*
758  * Name:		BIO_ds_dump_header
759  * Description:	Dumps all ds_headsize bytes from the
760  *		static 'ds_header_raw' character array
761  *		to the supplied BIO.
762  *
763  * Arguments:	err - where to record any errors.
764  *		bio - BIO object to dump data into
765  *
766  * Returns :	zero - successfully dumped all raw
767  *		header characters
768  *		non-zero - some failure occurred.
769  */
770 int
771 BIO_ds_dump_header(PKG_ERR *err, BIO *bio)
772 {
773 
774 	char	zeros[BLK_SIZE];
775 
776 	(void) memset(zeros, 0, BLK_SIZE);
777 
778 	if (BIO_write(bio, ds_header_raw, ds_headsize) != ds_headsize) {
779 		pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, "bio",
780 		    ERR_error_string(ERR_get_error(), NULL));
781 		return (1);
782 	}
783 
784 	return (0);
785 }
786 
787 /*
788  * ds_ginit: Determine the device being accessed, set the buffer size,
789  * and perform any device specific initialization.
790  */
791 
792 int
793 ds_ginit(char *device)
794 {
795 	int oflag;
796 	char *pbufsize, cmd[CMDSIZ];
797 	int fd2, fd;
798 
799 	if ((pbufsize = devattr(device, "bufsize")) != NULL) {
800 		ds_bufsize = atoi(pbufsize);
801 		(void) free(pbufsize);
802 	} else
803 		ds_bufsize = BLK_SIZE;
804 	oflag = fcntl(ds_fd, F_GETFL, 0);
805 
806 	if (ds_bufsize > BLK_SIZE) {
807 		if (oflag & O_WRONLY)
808 			fd = 1;
809 		else
810 			fd = 0;
811 		fd2 = fcntl(fd, F_DUPFD, fd);
812 		(void) close(fd);
813 		(void) fcntl(ds_fd, F_DUPFD, fd);
814 		if (fd)
815 			(void) snprintf(cmd, sizeof (cmd),
816 			    "%s obs=%d 2>/dev/null", DDPROC, ds_bufsize);
817 		else
818 			(void) snprintf(cmd, sizeof (cmd),
819 			    "%s ibs=%d 2>/dev/null", DDPROC, ds_bufsize);
820 		if ((ds_pp = popen(cmd, fd ? "w" : "r")) == NULL) {
821 			progerr(pkg_gt(ERR_TRANSFER));
822 			logerr(pkg_gt(MSG_POPEN), cmd, errno);
823 			return (-1);
824 		}
825 		(void) close(fd);
826 		(void) fcntl(fd2, F_DUPFD, fd);
827 		(void) close(fd2);
828 		ds_realfd = ds_fd;
829 		ds_fd = fileno(ds_pp);
830 	}
831 	return (ds_bufsize);
832 }
833 
834 int
835 ds_close(int pkgendflg)
836 {
837 	int n, ret = 0;
838 
839 	if (pkgendflg) {
840 		if (ds_header)
841 			(void) free(ds_header);
842 		ds_header = (char *)NULL;
843 		ds_totread = 0;
844 	}
845 
846 	if (ds_pp) {
847 		(void) pclose(ds_pp);
848 		ds_pp = 0;
849 		(void) close(ds_realfd);
850 		ds_realfd = -1;
851 		ds_fd = -1;
852 	} else if (ds_fd >= 0) {
853 		(void) close(ds_fd);
854 		ds_fd = -1;
855 	}
856 
857 	if (ds_device) {
858 		/* rewind device */
859 		if ((n = open(ds_device, 0)) >= 0)
860 			(void) close(n);
861 		ds_device = NULL;
862 	}
863 	return (ret);
864 }
865