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 #ifdef u3b2
46 #include <sys/sys3b.h>
47 #endif /* u3b2 */
48 #include <openssl/err.h>
49 #include "pkglib.h"
50 #include "pkglibmsgs.h"
51 #include "pkglocale.h"
52 #ifdef u3b2
53 static
54 struct stat orig_st_buf; /* Stat structure of original file (3B2/CTC) */
55 static char ds_ctcflg;
56 #endif /* u3b2 */
57
58 /* libadm.a */
59 extern char *devattr(char *device, char *attribute);
60 extern int pkgnmchk(register char *pkg, register char *spec,
61 int presvr4flg);
62 extern int getvol(char *device, char *label, int options, char *prompt);
63
64 #define CMDSIZ 512
65 #define LSIZE 128
66 #define DDPROC "/usr/bin/dd"
67 #define CPIOPROC "/usr/bin/cpio"
68
69 /* device types */
70
71 #define G_TM_TAPE 1 /* Tapemaster controller */
72 #define G_XY_DISK 3 /* xy disks */
73 #define G_SD_DISK 7 /* scsi sd disk */
74 #define G_XT_TAPE 8 /* xt tapes */
75 #define G_SF_FLOPPY 9 /* sf floppy */
76 #define G_XD_DISK 10 /* xd disks */
77 #define G_ST_TAPE 11 /* scsi tape */
78 #define G_NS 12 /* noswap pseudo-dev */
79 #define G_RAM 13 /* ram pseudo-dev */
80 #define G_FT 14 /* tftp */
81 #define G_HD 15 /* 386 network disk */
82 #define G_FD 16 /* 386 AT disk */
83 #define G_FILE 28 /* file, not a device */
84 #define G_NO_DEV 29 /* device does not require special treatment */
85 #define G_DEV_MAX 30 /* last valid device type */
86
87 struct dstoc {
88 int cnt;
89 char pkg[NON_ABI_NAMELNGTH];
90 int nparts;
91 long maxsiz;
92 char volnos[128];
93 struct dstoc *next;
94 } *ds_head, *ds_toc;
95
96 #define ds_nparts ds_toc->nparts
97 #define ds_maxsiz ds_toc->maxsiz
98
99 int ds_totread; /* total number of parts read */
100 int ds_fd = -1;
101 int ds_curpartcnt = -1;
102
103 int ds_next(char *device, char *instdir);
104 int ds_ginit(char *device);
105 int ds_close(int pkgendflg);
106
107 static FILE *ds_pp;
108 static int ds_realfd = -1; /* file descriptor for real device */
109 static int ds_read; /* number of parts read for current package */
110 static int ds_volno; /* volume number of current volume */
111 static int ds_volcnt; /* total number of volumes */
112 static char ds_volnos[128]; /* parts/volume info */
113 static char *ds_device;
114 static int ds_volpart; /* number of parts read in current volume, */
115 /* including skipped parts */
116 static int ds_bufsize;
117 static int ds_skippart; /* number of parts skipped in current volume */
118
119 static int ds_getnextvol(char *device);
120 static int ds_skip(char *device, int nskip);
121
122 void
ds_order(char * list[])123 ds_order(char *list[])
124 {
125 struct dstoc *toc_pt;
126 register int j, n;
127 char *pt;
128
129 toc_pt = ds_head;
130 n = 0;
131 while (toc_pt) {
132 for (j = n; list[j]; j++) {
133 if (strcmp(list[j], toc_pt->pkg) == 0) {
134 /* just swap places in the array */
135 pt = list[n];
136 list[n++] = list[j];
137 list[j] = pt;
138 }
139 }
140 toc_pt = toc_pt->next;
141 }
142 }
143
144 static char *pds_header;
145 static char *ds_header;
146 static char *ds_header_raw;
147 static int ds_headsize;
148
149 static char *
ds_gets(char * buf,int size)150 ds_gets(char *buf, int size)
151 {
152 int length;
153 char *nextp;
154
155 nextp = strchr(pds_header, '\n');
156 if (nextp == NULL) {
157 length = strlen(pds_header);
158 if (length > size)
159 return (0);
160 if ((ds_header = (char *)realloc(ds_header,
161 ds_headsize + BLK_SIZE)) == NULL)
162 return (0);
163 if (read(ds_fd, ds_header + ds_headsize, BLK_SIZE) < BLK_SIZE)
164 return (0);
165 ds_headsize += BLK_SIZE;
166 nextp = strchr(pds_header, '\n');
167 if (nextp == NULL)
168 return (0);
169 *nextp = '\0';
170 if (length + (int)strlen(pds_header) > size)
171 return (0);
172 (void) strncpy(buf + length, pds_header, strlen(pds_header));
173 buf[length + strlen(pds_header)] = '\0';
174 pds_header = nextp + 1;
175 return (buf);
176 }
177 *nextp = '\0';
178 if ((int)strlen(pds_header) > size)
179 return (0);
180 (void) strncpy(buf, pds_header, strlen(pds_header));
181 buf[strlen(pds_header)] = '\0';
182 pds_header = nextp + 1;
183 return (buf);
184 }
185
186 /*
187 * function to determine if media is datastream or mounted
188 * floppy
189 */
190 int
ds_readbuf(char * device)191 ds_readbuf(char *device)
192 {
193 char buf[BLK_SIZE];
194
195 if (ds_fd >= 0)
196 (void) close(ds_fd);
197 if ((ds_fd = open(device, O_RDONLY)) >= 0 &&
198 read(ds_fd, buf, BLK_SIZE) == BLK_SIZE &&
199 strncmp(buf, HDR_PREFIX, 20) == 0) {
200 if ((ds_header = (char *)calloc(BLK_SIZE, 1)) == NULL) {
201 progerr(pkg_gt(ERR_UNPACK));
202 logerr(pkg_gt(MSG_MEM));
203 (void) ds_close(0);
204 return (0);
205 }
206 memcpy(ds_header, buf, BLK_SIZE);
207 ds_headsize = BLK_SIZE;
208
209 if (ds_ginit(device) < 0) {
210 progerr(pkg_gt(ERR_UNPACK));
211 logerr(pkg_gt(MSG_OPEN), device, errno);
212 (void) ds_close(0);
213 return (0);
214 }
215 return (1);
216 } else if (ds_fd >= 0) {
217 (void) close(ds_fd);
218 ds_fd = -1;
219 }
220 return (0);
221 }
222
223 /*
224 * Determine how many additional volumes are needed for current package.
225 * Note: a 0 will occur as first volume number when the package begins
226 * on the next volume.
227 */
228 static int
ds_volsum(struct dstoc * toc)229 ds_volsum(struct dstoc *toc)
230 {
231 int curpartcnt, volcnt;
232 char volnos[128], tmpvol[128];
233 if (toc->volnos[0]) {
234 int index, sum;
235 sscanf(toc->volnos, "%d %[ 0-9]", &curpartcnt, volnos);
236 volcnt = 0;
237 sum = curpartcnt;
238 while (sum < toc->nparts && sscanf(volnos, "%d %[ 0-9]",
239 &index, tmpvol) >= 1) {
240 (void) strcpy(volnos, tmpvol);
241 volcnt++;
242 sum += index;
243 }
244 /* side effect - set number of parts read on current volume */
245 ds_volpart = index;
246 return (volcnt);
247 }
248 ds_volpart += toc->nparts;
249 return (0);
250 }
251
252 /* initialize ds_curpartcnt and ds_volnos */
253 static void
ds_pkginit(void)254 ds_pkginit(void)
255 {
256 if (ds_toc->volnos[0])
257 sscanf(ds_toc->volnos, "%d %[ 0-9]", &ds_curpartcnt, ds_volnos);
258 else
259 ds_curpartcnt = -1;
260 }
261
262 /*
263 * functions to pass current package info to exec'ed program
264 */
265 void
ds_putinfo(char * buf)266 ds_putinfo(char *buf)
267 {
268 (void) sprintf(buf, "%d %d %d %d %d %d %d %d %d %d %s",
269 ds_fd, ds_realfd, ds_volcnt, ds_volno, ds_totread, ds_volpart,
270 ds_skippart, ds_bufsize, ds_toc->nparts, ds_toc->maxsiz,
271 ds_toc->volnos);
272 }
273
274 int
ds_getinfo(char * string)275 ds_getinfo(char *string)
276 {
277 ds_toc = (struct dstoc *)calloc(1, sizeof (struct dstoc));
278 (void) sscanf(string, "%d %d %d %d %d %d %d %d %d %d %[ 0-9]",
279 &ds_fd, &ds_realfd, &ds_volcnt, &ds_volno, &ds_totread,
280 &ds_volpart, &ds_skippart, &ds_bufsize, &ds_toc->nparts,
281 &ds_toc->maxsiz, ds_toc->volnos);
282 ds_pkginit();
283 return (ds_toc->nparts);
284 }
285
286 /*
287 * Return true if the file descriptor (ds_fd) is open on the package stream.
288 */
289 boolean_t
ds_fd_open(void)290 ds_fd_open(void)
291 {
292 return (ds_fd >= 0 ? B_TRUE : B_FALSE);
293 }
294
295 /*
296 * Read the source device. Acquire the header data and check it for validity.
297 */
298 int
ds_init(char * device,char ** pkg,char * norewind)299 ds_init(char *device, char **pkg, char *norewind)
300 {
301 struct dstoc *tail, *toc_pt;
302 char *ret;
303 char cmd[CMDSIZ];
304 char line[LSIZE+1];
305 int i, n, count = 0, header_size = BLK_SIZE;
306
307 if (!ds_header) { /* If the header hasn't been read yet */
308 if (ds_fd >= 0)
309 (void) ds_close(0);
310
311 /* always start with rewind device */
312 if ((ds_fd = open(device, O_RDONLY)) < 0) {
313 progerr(pkg_gt(ERR_UNPACK));
314 logerr(pkg_gt(MSG_OPEN), device, errno);
315 return (-1);
316 }
317
318 /* allocate room for the header equivalent to a block */
319 if ((ds_header = (char *)calloc(BLK_SIZE, 1)) == NULL) {
320 progerr(pkg_gt(ERR_UNPACK));
321 logerr(pkg_gt(MSG_MEM));
322 return (-1);
323 }
324
325 /* initialize the device */
326 if (ds_ginit(device) < 0) {
327 (void) ds_close(0);
328 progerr(pkg_gt(ERR_UNPACK));
329 logerr(pkg_gt(MSG_OPEN), device, errno);
330 return (-1);
331 }
332
333 /* read a logical block from the source device */
334 if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) {
335 rpterr();
336 progerr(pkg_gt(ERR_UNPACK));
337 logerr(pkg_gt(MSG_TOC));
338 (void) ds_close(0);
339 return (-1);
340 }
341
342 /*
343 * This loop scans the medium for the start of the header.
344 * If the above read worked, we skip this. If it did't, this
345 * loop will retry the read ten times looking for the header
346 * marker string.
347 */
348 while (strncmp(ds_header, HDR_PREFIX, 20) != 0) {
349 /* only ten tries iff the device rewinds */
350 if (!norewind || count++ > 10) {
351 progerr(pkg_gt(ERR_UNPACK));
352 logerr(pkg_gt(MSG_TOC));
353 (void) ds_close(0);
354 return (-1);
355 }
356
357 /* read through to the last block */
358 if (count > 1)
359 while (read(ds_fd, ds_header, BLK_SIZE) > 0)
360 ;
361
362 /* then close the device */
363 (void) ds_close(0);
364
365 /* and reopen it */
366 if ((ds_fd = open(norewind, O_RDONLY)) < 0) {
367 progerr(pkg_gt(ERR_UNPACK));
368 logerr(pkg_gt(MSG_OPEN), device, errno);
369 (void) free(ds_header);
370 return (-1);
371 }
372
373 /* initialize the device */
374 if (ds_ginit(device) < 0) {
375 (void) ds_close(0);
376 progerr(pkg_gt(ERR_UNPACK));
377 logerr(pkg_gt(MSG_OPEN), device, errno);
378 return (-1);
379 }
380
381 /* read the block again */
382 if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) {
383 rpterr();
384 progerr(pkg_gt(ERR_UNPACK));
385 logerr(pkg_gt(MSG_TOC));
386 (void) ds_close(0);
387 return (-1);
388 }
389 }
390
391 /* Now keep scanning until the whole header is in place. */
392 while (strstr(ds_header, HDR_SUFFIX) == NULL) {
393 /* We need a bigger buffer */
394 if ((ds_header = (char *)realloc(ds_header,
395 header_size + BLK_SIZE)) == NULL) {
396 progerr(pkg_gt(ERR_UNPACK));
397 logerr(pkg_gt(MSG_MEM));
398 (void) ds_close(0);
399 return (1);
400 }
401
402 /* clear the new memory */
403 (void) memset(ds_header + header_size, '\0',
404 BLK_SIZE);
405
406
407 /* read a logical block from the source device */
408 if (read(ds_fd, ds_header + header_size, BLK_SIZE) !=
409 BLK_SIZE) {
410 rpterr();
411 progerr(pkg_gt(ERR_UNPACK));
412 logerr(pkg_gt(MSG_TOC));
413 (void) ds_close(0);
414 return (-1);
415 } else
416 header_size += BLK_SIZE; /* new size */
417 }
418
419 /*
420 * remember rewind device for ds_close to rewind at
421 * close
422 */
423 if (count >= 1)
424 ds_device = device;
425 ds_headsize = header_size;
426
427 }
428
429 pds_header = ds_header;
430
431 /* save raw copy of header for later use in BIO_dump_header */
432 if ((ds_header_raw = (char *)malloc(header_size)) == NULL) {
433 progerr(pkg_gt(ERR_UNPACK));
434 logerr(pkg_gt(MSG_MEM));
435 (void) ds_close(0);
436 return (1);
437 }
438 memcpy(ds_header_raw, ds_header, header_size);
439
440 /* read datastream table of contents */
441 ds_head = tail = (struct dstoc *)0;
442 ds_volcnt = 1;
443
444 while (ret = ds_gets(line, LSIZE)) {
445 if (strcmp(line, HDR_SUFFIX) == 0)
446 break;
447 if (!line[0] || line[0] == '#')
448 continue;
449 toc_pt = (struct dstoc *)calloc(1, sizeof (struct dstoc));
450 if (!toc_pt) {
451 progerr(pkg_gt(ERR_UNPACK));
452 logerr(pkg_gt(MSG_MEM));
453 ecleanup();
454 (void) free(ds_header);
455 return (-1);
456 }
457 if (sscanf(line, "%s %d %d %[ 0-9]", toc_pt->pkg,
458 &toc_pt->nparts, &toc_pt->maxsiz, toc_pt->volnos) < 3) {
459 progerr(pkg_gt(ERR_UNPACK));
460 logerr(pkg_gt(MSG_TOC));
461 free(toc_pt);
462 (void) free(ds_header);
463 ecleanup();
464 return (-1);
465 }
466 if (tail) {
467 tail->next = toc_pt;
468 tail = toc_pt;
469 } else
470 ds_head = tail = toc_pt;
471 ds_volcnt += ds_volsum(toc_pt);
472 }
473 if (!ret) {
474 progerr(pkg_gt(ERR_UNPACK));
475 logerr(pkg_gt(MSG_TOC));
476 (void) free(ds_header);
477 return (-1);
478 }
479 sighold(SIGINT);
480 sigrelse(SIGINT);
481 if (!ds_head) {
482 progerr(pkg_gt(ERR_UNPACK));
483 logerr(pkg_gt(MSG_EMPTY));
484 (void) free(ds_header);
485 return (-1);
486 }
487 /* this could break, thanks to cpio command limit */
488 #ifndef SUNOS41
489 (void) sprintf(cmd, "%s -icdumD -C %d", CPIOPROC, (int)BLK_SIZE);
490 #else
491 (void) sprintf(cmd, "%s -icdum -C %d", CPIOPROC, (int)BLK_SIZE);
492 #endif
493 n = 0;
494 for (i = 0; pkg[i]; i++) {
495 if (strcmp(pkg[i], "all") == 0)
496 continue;
497 if (n == 0) {
498 strcat(cmd, " ");
499 n = 1;
500 }
501 strlcat(cmd, pkg[i], CMDSIZ);
502 strlcat(cmd, "'/*' ", CMDSIZ);
503
504 /* extract signature too, if present. */
505 strlcat(cmd, SIGNATURE_FILENAME, CMDSIZ);
506 strlcat(cmd, " ", CMDSIZ);
507 }
508
509 /*
510 * if we are extracting all packages (pkgs == NULL),
511 * signature will automatically be extracted
512 */
513 if (n = esystem(cmd, ds_fd, -1)) {
514 rpterr();
515 progerr(pkg_gt(ERR_UNPACK));
516 logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
517 (void) free(ds_header);
518 return (-1);
519 }
520
521 ds_toc = ds_head;
522 ds_totread = 0;
523 ds_volno = 1;
524 return (0);
525 }
526
527 int
ds_findpkg(char * device,char * pkg)528 ds_findpkg(char *device, char *pkg)
529 {
530 char *pkglist[2];
531 int nskip, ods_volpart;
532
533 if (ds_head == NULL) {
534 pkglist[0] = pkg;
535 pkglist[1] = NULL;
536 if (ds_init(device, pkglist, NULL))
537 return (-1);
538 }
539
540 if (!pkg || pkgnmchk(pkg, "all", 0)) {
541 progerr(pkg_gt(ERR_UNPACK));
542 logerr(pkg_gt(MSG_PKGNAME));
543 return (-1);
544 }
545
546 nskip = 0;
547 ds_volno = 1;
548 ds_volpart = 0;
549 ds_toc = ds_head;
550 while (ds_toc) {
551 if (strcmp(ds_toc->pkg, pkg) == 0)
552 break;
553 nskip += ds_toc->nparts;
554 ds_volno += ds_volsum(ds_toc);
555 ds_toc = ds_toc->next;
556 }
557 if (!ds_toc) {
558 progerr(pkg_gt(ERR_UNPACK));
559 logerr(pkg_gt(MSG_NOPKG), pkg);
560 return (-1);
561 }
562
563 ds_pkginit();
564 ds_skippart = 0;
565 if (ds_curpartcnt > 0) {
566 ods_volpart = ds_volpart;
567 /*
568 * skip past archives belonging to last package on current
569 * volume
570 */
571 if (ds_volpart > 0 && ds_getnextvol(device))
572 return (-1);
573 ds_totread = nskip - ods_volpart;
574 if (ds_skip(device, ods_volpart))
575 return (-1);
576 } else if (ds_curpartcnt < 0) {
577 if (ds_skip(device, nskip - ds_totread))
578 return (-1);
579 } else
580 ds_totread = nskip;
581 ds_read = 0;
582 return (ds_nparts);
583 }
584
585 /*
586 * Get datastream part
587 * Call for first part should be preceded by
588 * call to ds_findpkg
589 */
590
591 int
ds_getpkg(char * device,int n,char * dstdir)592 ds_getpkg(char *device, int n, char *dstdir)
593 {
594 struct statvfs64 svfsb;
595 u_longlong_t free_blocks;
596
597 if (ds_read >= ds_nparts)
598 return (2);
599
600 if (ds_read == n)
601 return (0);
602 else if ((ds_read > n) || (n > ds_nparts))
603 return (2);
604
605 if (ds_maxsiz > 0) {
606 if (statvfs64(".", &svfsb)) {
607 progerr(pkg_gt(ERR_UNPACK));
608 logerr(pkg_gt(MSG_STATFS), errno);
609 return (-1);
610 }
611 #ifdef SUNOS41
612 free_blocks = svfsb.f_bfree * howmany(svfsb.f_bsize, DEV_BSIZE);
613 #else /* !SUNOS41 */
614 free_blocks = (((long)svfsb.f_frsize > 0) ?
615 howmany(svfsb.f_frsize, DEV_BSIZE) :
616 howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
617 #endif /* SUNOS41 */
618 if ((ds_maxsiz + 50) > free_blocks) {
619 progerr(pkg_gt(ERR_UNPACK));
620 logerr(pkg_gt(MSG_NOSPACE), ds_maxsiz+50, free_blocks);
621 return (-1);
622 }
623 }
624 return (ds_next(device, dstdir));
625 }
626
627 static int
ds_getnextvol(char * device)628 ds_getnextvol(char *device)
629 {
630 char prompt[128];
631 int n;
632
633 if (ds_close(0))
634 return (-1);
635 (void) sprintf(prompt,
636 pkg_gt("Insert %%v %d of %d into %%p"),
637 ds_volno, ds_volcnt);
638 if (n = getvol(device, NULL, NULL, prompt))
639 return (n);
640 if ((ds_fd = open(device, O_RDONLY)) < 0)
641 return (-1);
642 if (ds_ginit(device) < 0) {
643 (void) ds_close(0);
644 return (-1);
645 }
646 ds_volpart = 0;
647 return (0);
648 }
649
650 /*
651 * called by ds_findpkg to skip past archives for unwanted packages
652 * in current volume
653 */
654 static int
ds_skip(char * device,int nskip)655 ds_skip(char *device, int nskip)
656 {
657 char cmd[CMDSIZ];
658 int n, onskip = nskip;
659
660 while (nskip--) {
661 /* skip this one */
662 #ifndef SUNOS41
663 (void) sprintf(cmd, "%s -ictD -C %d > /dev/null",
664 #else
665 (void) sprintf(cmd, "%s -ict -C %d > /dev/null",
666 #endif
667 CPIOPROC, (int)BLK_SIZE);
668 if (n = esystem(cmd, ds_fd, -1)) {
669 rpterr();
670 progerr(pkg_gt(ERR_UNPACK));
671 logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
672 nskip = onskip;
673 if (ds_volno == 1 || ds_volpart > 0)
674 return (n);
675 if (n = ds_getnextvol(device))
676 return (n);
677 }
678 }
679 ds_totread += onskip;
680 ds_volpart = onskip;
681 ds_skippart = onskip;
682 return (0);
683 }
684
685 /* skip to end of package if necessary */
686 void
ds_skiptoend(char * device)687 ds_skiptoend(char *device)
688 {
689 if (ds_read < ds_nparts && ds_curpartcnt < 0)
690 (void) ds_skip(device, ds_nparts - ds_read);
691 }
692
693 int
ds_next(char * device,char * instdir)694 ds_next(char *device, char *instdir)
695 {
696 char cmd[CMDSIZ], tmpvol[128];
697 int nparts, n, index;
698
699 /*CONSTCOND*/
700 while (1) {
701 if (ds_read + 1 > ds_curpartcnt && ds_curpartcnt >= 0) {
702 ds_volno++;
703 if (n = ds_getnextvol(device))
704 return (n);
705 (void) sscanf(ds_volnos, "%d %[ 0-9]", &index, tmpvol);
706 (void) strcpy(ds_volnos, tmpvol);
707 ds_curpartcnt += index;
708 }
709 #ifndef SUNOS41
710 (void) sprintf(cmd, "%s -icdumD -C %d",
711 #else
712 (void) sprintf(cmd, "%s -icdum -C %d",
713 #endif
714 CPIOPROC, (int)BLK_SIZE);
715 if (n = esystem(cmd, ds_fd, -1)) {
716 rpterr();
717 progerr(pkg_gt(ERR_UNPACK));
718 logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
719 }
720 if (ds_read == 0)
721 nparts = 0;
722 else
723 nparts = ds_toc->nparts;
724 if (n || (n = ckvolseq(instdir, ds_read + 1, nparts))) {
725 if (ds_volno == 1 || ds_volpart > ds_skippart)
726 return (-1);
727
728 if (n = ds_getnextvol(device))
729 return (n);
730 continue;
731 }
732 ds_read++;
733 ds_totread++;
734 ds_volpart++;
735
736 return (0);
737 }
738 /*NOTREACHED*/
739 }
740
741 /*
742 * Name: BIO_ds_dump
743 * Description: Dumps all data from the static 'ds_fd' file handle into
744 * the supplied BIO.
745 *
746 * Arguments: err - where to record any errors.
747 * device - Description of device being dumped into,
748 * for error reporting
749 * bio - BIO object to dump data into
750 *
751 * Returns : zero - successfully dumped all data to EOF
752 * non-zero - some failure occurred.
753 */
754 int
BIO_ds_dump(PKG_ERR * err,char * device,BIO * bio)755 BIO_ds_dump(PKG_ERR *err, char *device, BIO *bio)
756 {
757 int amtread;
758 char readbuf[BLK_SIZE];
759
760 /*
761 * note this will read to the end of the device, so it won't
762 * work for character devices since we don't know when the
763 * end of the CPIO archive is
764 */
765 while ((amtread = read(ds_fd, readbuf, BLK_SIZE)) != 0) {
766 if (BIO_write(bio, readbuf, amtread) != amtread) {
767 pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, device,
768 ERR_error_string(ERR_get_error(), NULL));
769 return (1);
770 }
771 }
772
773 return (0);
774 /*NOTREACHED*/
775 }
776
777
778 /*
779 * Name: BIO_ds_dump_header
780 * Description: Dumps all ds_headsize bytes from the
781 * static 'ds_header_raw' character array
782 * to the supplied BIO.
783 *
784 * Arguments: err - where to record any errors.
785 * bio - BIO object to dump data into
786 *
787 * Returns : zero - successfully dumped all raw
788 * header characters
789 * non-zero - some failure occurred.
790 */
791 int
BIO_ds_dump_header(PKG_ERR * err,BIO * bio)792 BIO_ds_dump_header(PKG_ERR *err, BIO *bio)
793 {
794
795 char zeros[BLK_SIZE];
796
797 memset(zeros, 0, BLK_SIZE);
798
799 if (BIO_write(bio, ds_header_raw, ds_headsize) != ds_headsize) {
800 pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, "bio",
801 ERR_error_string(ERR_get_error(), NULL));
802 return (1);
803 }
804
805 return (0);
806 }
807
808 /*
809 * ds_ginit: Determine the device being accessed, set the buffer size,
810 * and perform any device specific initialization. For the 3B2,
811 * a device with major number of 17 (0x11) is an internal hard disk,
812 * unless the minor number is 128 (0x80) in which case it is an internal
813 * floppy disk. Otherwise, get the system configuration
814 * table and check it by comparing slot numbers to major numbers.
815 * For the special case of the 3B2 CTC several unusual things must be done.
816 * To enable
817 * streaming mode on the CTC, the file descriptor must be closed, re-opened
818 * (with O_RDWR and O_CTSPECIAL flags set), the STREAMON ioctl(2) command
819 * issued, and the file descriptor re-re-opened either read-only or write_only.
820 */
821
822 int
ds_ginit(char * device)823 ds_ginit(char *device)
824 {
825 #ifdef u3b2
826 major_t maj;
827 minor_t min;
828 int nflag, i, count, size;
829 struct s3bconf *buffer;
830 struct s3bc *table;
831 struct stat st_buf;
832 int devtype;
833 char buf[BLK_SIZE];
834 int fd2, fd;
835 #endif /* u3b2 */
836 int oflag;
837 char *pbufsize, cmd[CMDSIZ];
838 int fd2, fd;
839
840 if ((pbufsize = devattr(device, "bufsize")) != NULL) {
841 ds_bufsize = atoi(pbufsize);
842 (void) free(pbufsize);
843 } else
844 ds_bufsize = BLK_SIZE;
845 oflag = fcntl(ds_fd, F_GETFL, 0);
846 #ifdef u3b2
847 devtype = G_NO_DEV;
848 if (fstat(ds_fd, &st_buf) == -1)
849 return (-1);
850 if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode))
851 goto lab;
852
853 /*
854 * We'll have to add a remote attribute to stat but this should
855 * work for now.
856 */
857 else if (st_buf.st_dev & 0x8000) /* if remote rdev */
858 goto lab;
859
860 maj = major(st_buf.st_rdev);
861 min = minor(st_buf.st_rdev);
862 if (maj == 0x11) { /* internal hard or floppy disk */
863 if (min & 0x80)
864 devtype = G_3B2_FD; /* internal floppy disk */
865 else
866 devtype = G_3B2_HD; /* internal hard disk */
867 } else {
868 if (sys3b(S3BCONF, (struct s3bconf *)&count, sizeof (count)) ==
869 -1)
870 return (-1);
871 size = sizeof (int) + (count * sizeof (struct s3bconf));
872 buffer = (struct s3bconf *)malloc((unsigned)size);
873 if (sys3b(S3BCONF, buffer, size) == -1)
874 return (-1);
875 table = (struct s3bc *)((char *)buffer + sizeof (int));
876 for (i = 0; i < count; i++) {
877 if (maj == (int)table->board) {
878 if (strncmp(table->name, "CTC", 3) == 0) {
879 devtype = G_3B2_CTC;
880 break;
881 } else if (strncmp(table->name, "TAPE", 4)
882 == 0) {
883 devtype = G_TAPE;
884 break;
885 }
886 /* other possible devices can go here */
887 }
888 table++;
889 }
890 }
891 switch (devtype) {
892 case G_3B2_CTC: /* do special CTC initialization */
893 ds_bufsize = pbufsize ? ds_bufsize : 15872;
894 if (fstat(ds_fd, &orig_st_buf) < 0) {
895 ds_bufsize = -1;
896 break;
897 }
898 nflag = (O_RDWR | O_CTSPECIAL);
899 (void) close(ds_fd);
900 if ((ds_fd = open(device, nflag, 0666)) != -1) {
901 if (ioctl(ds_fd, STREAMON) != -1) {
902 (void) close(ds_fd);
903 nflag = (oflag == O_WRONLY) ?
904 O_WRONLY : O_RDONLY;
905 if ((ds_fd =
906 open(device, nflag, 0666)) == -1) {
907 rpterr();
908 progerr(
909 pkg_gt(ERR_TRANSFER));
910 logerr(pkg_gt(MSG_OPEN),
911 device, errno);
912 return (-1);
913 }
914 ds_bufsize = 15872;
915 }
916 } else
917 ds_bufsize = -1;
918 if (oflag == O_RDONLY && ds_header && ds_totread == 0)
919 /* Have already read in first block of header */
920 read(ds_fd, buf, BLK_SIZE);
921 ds_ctcflg = 1;
922
923 break;
924 case G_NO_DEV:
925 case G_3B2_HD:
926 case G_3B2_FD:
927 case G_TAPE:
928 case G_SCSI_HD: /* not developed yet */
929 case G_SCSI_FD:
930 case G_SCSI_9T:
931 case G_SCSI_Q24:
932 case G_SCSI_Q120:
933 case G_386_HD:
934 case G_386_FD:
935 case G_386_Q24:
936 ds_bufsize = pbufsize ? ds_bufsize : BLK_SIZE;
937 break;
938 default:
939 ds_bufsize = -1;
940 errno = ENODEV;
941 } /* devtype */
942 lab:
943 #endif /* u3b2 */
944 if (ds_bufsize > BLK_SIZE) {
945 if (oflag & O_WRONLY)
946 fd = 1;
947 else
948 fd = 0;
949 fd2 = fcntl(fd, F_DUPFD, fd);
950 (void) close(fd);
951 fcntl(ds_fd, F_DUPFD, fd);
952 if (fd)
953 sprintf(cmd, "%s obs=%d 2>/dev/null", DDPROC,
954 ds_bufsize);
955 else
956 sprintf(cmd, "%s ibs=%d 2>/dev/null", DDPROC,
957 ds_bufsize);
958 if ((ds_pp = popen(cmd, fd ? "w" : "r")) == NULL) {
959 progerr(pkg_gt(ERR_TRANSFER));
960 logerr(pkg_gt(MSG_POPEN), cmd, errno);
961 return (-1);
962 }
963 (void) close(fd);
964 fcntl(fd2, F_DUPFD, fd);
965 (void) close(fd2);
966 ds_realfd = ds_fd;
967 ds_fd = fileno(ds_pp);
968 }
969 return (ds_bufsize);
970 }
971
972 int
ds_close(int pkgendflg)973 ds_close(int pkgendflg)
974 {
975 #ifdef u3b2
976 int cnt, mode;
977 char *ptr;
978 struct stat statbuf;
979 #endif /* u3b2 */
980 int n, ret = 0;
981
982 #ifdef u3b2
983 if (ds_pp && ds_ctcflg) {
984 ds_ctcflg = 0;
985 if ((mode = fcntl(ds_realfd, F_GETFL, 0)) < 0) {
986 ret = -1;
987 } else if (mode & O_WRONLY) {
988 /*
989 * pipe to dd write process,
990 * make sure one more buffer
991 * gets written out
992 */
993 if ((ptr = calloc(BLK_SIZE, 1)) == NULL) {
994 ret = -1;
995 /* pad to bufsize */
996 } else {
997 cnt = ds_bufsize;
998 while (cnt > 0) {
999 if ((n = write(ds_fd, ptr,
1000 BLK_SIZE)) < 0) {
1001 ret = -1;
1002 break;
1003 }
1004 cnt -= n;
1005 }
1006 (void) free(ptr);
1007 }
1008 }
1009 }
1010 #endif
1011 if (pkgendflg) {
1012 if (ds_header)
1013 (void) free(ds_header);
1014 ds_header = (char *)NULL;
1015 ds_totread = 0;
1016 }
1017
1018 if (ds_pp) {
1019 (void) pclose(ds_pp);
1020 ds_pp = 0;
1021 (void) close(ds_realfd);
1022 ds_realfd = -1;
1023 ds_fd = -1;
1024 } else if (ds_fd >= 0) {
1025 (void) close(ds_fd);
1026 ds_fd = -1;
1027 }
1028
1029 if (ds_device) {
1030 /* rewind device */
1031 if ((n = open(ds_device, 0)) >= 0)
1032 (void) close(n);
1033 ds_device = NULL;
1034 }
1035 return (ret);
1036 }
1037