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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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