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 (c) 2017 Peter Tribble. 24 */ 25 26 /* 27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 32 /* All Rights Reserved */ 33 34 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <signal.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <sys/param.h> 43 #include <sys/sysmacros.h> 44 #include <errno.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <sys/statvfs.h> 48 #include <fcntl.h> 49 #include "pkglib.h" 50 #include "pkglibmsgs.h" 51 #include "pkglocale.h" 52 53 /* libadm.a */ 54 extern char *devattr(char *device, char *attribute); 55 extern int pkgnmchk(register char *pkg, register char *spec, 56 int presvr4flg); 57 extern int getvol(char *device, char *label, int options, char *prompt); 58 59 #define CMDSIZ 512 60 #define LSIZE 128 61 #define DDPROC "/usr/bin/dd" 62 #define CPIOPROC "/usr/bin/cpio" 63 64 /* device types */ 65 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 */ 81 82 struct dstoc { 83 int cnt; 84 char pkg[NON_ABI_NAMELNGTH]; 85 int nparts; 86 long maxsiz; 87 char volnos[128]; 88 struct dstoc *next; 89 } *ds_head, *ds_toc; 90 91 #define ds_nparts ds_toc->nparts 92 #define ds_maxsiz ds_toc->maxsiz 93 94 int ds_totread; /* total number of parts read */ 95 int ds_fd = -1; 96 int ds_curpartcnt = -1; 97 98 int ds_next(char *device, char *instdir); 99 int ds_ginit(char *device); 100 int ds_close(int pkgendflg); 101 102 static FILE *ds_pp; 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 */ 113 114 static int ds_getnextvol(char *device); 115 static int ds_skip(char *device, int nskip); 116 117 void 118 ds_order(char *list[]) 119 { 120 struct dstoc *toc_pt; 121 register int j, n; 122 char *pt; 123 124 toc_pt = ds_head; 125 n = 0; 126 while (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 */ 130 pt = list[n]; 131 list[n++] = list[j]; 132 list[j] = pt; 133 } 134 } 135 toc_pt = toc_pt->next; 136 } 137 } 138 139 static char *pds_header; 140 static char *ds_header; 141 static int ds_headsize; 142 143 static char * 144 ds_gets(char *buf, int size) 145 { 146 int length; 147 char *nextp; 148 149 nextp = strchr(pds_header, '\n'); 150 if (nextp == NULL) { 151 length = strlen(pds_header); 152 if (length > size) 153 return (0); 154 if ((ds_header = (char *)realloc(ds_header, 155 ds_headsize + BLK_SIZE)) == NULL) 156 return (0); 157 if (read(ds_fd, ds_header + ds_headsize, BLK_SIZE) < BLK_SIZE) 158 return (0); 159 ds_headsize += BLK_SIZE; 160 nextp = strchr(pds_header, '\n'); 161 if (nextp == NULL) 162 return (0); 163 *nextp = '\0'; 164 if (length + (int)strlen(pds_header) > size) 165 return (0); 166 (void) strncpy(buf + length, pds_header, strlen(pds_header)); 167 buf[length + strlen(pds_header)] = '\0'; 168 pds_header = nextp + 1; 169 return (buf); 170 } 171 *nextp = '\0'; 172 if ((int)strlen(pds_header) > size) 173 return (0); 174 (void) strncpy(buf, pds_header, strlen(pds_header)); 175 buf[strlen(pds_header)] = '\0'; 176 pds_header = nextp + 1; 177 return (buf); 178 } 179 180 /* 181 * function to determine if media is datastream or mounted 182 * floppy 183 */ 184 int 185 ds_readbuf(char *device) 186 { 187 char buf[BLK_SIZE]; 188 189 if (ds_fd >= 0) 190 (void) close(ds_fd); 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)); 197 (void) ds_close(0); 198 return (0); 199 } 200 (void) memcpy(ds_header, buf, BLK_SIZE); 201 ds_headsize = BLK_SIZE; 202 203 if (ds_ginit(device) < 0) { 204 progerr(pkg_gt(ERR_UNPACK)); 205 logerr(pkg_gt(MSG_OPEN), device, errno); 206 (void) ds_close(0); 207 return (0); 208 } 209 return (1); 210 } else if (ds_fd >= 0) { 211 (void) close(ds_fd); 212 ds_fd = -1; 213 } 214 return (0); 215 } 216 217 /* 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. 221 */ 222 static int 223 ds_volsum(struct dstoc *toc) 224 { 225 int curpartcnt, volcnt; 226 char volnos[128], tmpvol[128]; 227 if (toc->volnos[0]) { 228 int index, sum; 229 (void) sscanf(toc->volnos, "%d %[ 0-9]", &curpartcnt, volnos); 230 volcnt = 0; 231 sum = curpartcnt; 232 while (sum < toc->nparts && sscanf(volnos, "%d %[ 0-9]", 233 &index, tmpvol) >= 1) { 234 (void) strcpy(volnos, tmpvol); 235 volcnt++; 236 sum += index; 237 } 238 /* side effect - set number of parts read on current volume */ 239 ds_volpart = index; 240 return (volcnt); 241 } 242 ds_volpart += toc->nparts; 243 return (0); 244 } 245 246 /* initialize ds_curpartcnt and ds_volnos */ 247 static void 248 ds_pkginit(void) 249 { 250 if (ds_toc->volnos[0]) 251 (void) sscanf(ds_toc->volnos, "%d %[ 0-9]", &ds_curpartcnt, 252 ds_volnos); 253 else 254 ds_curpartcnt = -1; 255 } 256 257 /* 258 * functions to pass current package info to exec'ed program 259 */ 260 void 261 ds_putinfo(char *buf, size_t sz) 262 { 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, 266 ds_toc->volnos); 267 } 268 269 int 270 ds_getinfo(char *string) 271 { 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); 277 ds_pkginit(); 278 return (ds_toc->nparts); 279 } 280 281 /* 282 * Return true if the file descriptor (ds_fd) is open on the package stream. 283 */ 284 boolean_t 285 ds_fd_open(void) 286 { 287 return (ds_fd >= 0 ? B_TRUE : B_FALSE); 288 } 289 290 /* 291 * Read the source device. Acquire the header data and check it for validity. 292 */ 293 int 294 ds_init(char *device, char **pkg, char *norewind) 295 { 296 struct dstoc *tail, *toc_pt; 297 char *ret; 298 char cmd[CMDSIZ]; 299 char line[LSIZE+1]; 300 int i, n, count = 0, header_size = BLK_SIZE; 301 302 if (!ds_header) { /* If the header hasn't been read yet */ 303 if (ds_fd >= 0) 304 (void) ds_close(0); 305 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); 310 return (-1); 311 } 312 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)); 317 return (-1); 318 } 319 320 /* initialize the device */ 321 if (ds_ginit(device) < 0) { 322 (void) ds_close(0); 323 progerr(pkg_gt(ERR_UNPACK)); 324 logerr(pkg_gt(MSG_OPEN), device, errno); 325 return (-1); 326 } 327 328 /* read a logical block from the source device */ 329 if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) { 330 rpterr(); 331 progerr(pkg_gt(ERR_UNPACK)); 332 logerr(pkg_gt(MSG_TOC)); 333 (void) ds_close(0); 334 return (-1); 335 } 336 337 /* 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 341 * marker string. 342 */ 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)); 348 (void) ds_close(0); 349 return (-1); 350 } 351 352 /* read through to the last block */ 353 if (count > 1) 354 while (read(ds_fd, ds_header, BLK_SIZE) > 0) 355 ; 356 357 /* then close the device */ 358 (void) ds_close(0); 359 360 /* and reopen it */ 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); 365 return (-1); 366 } 367 368 /* initialize the device */ 369 if (ds_ginit(device) < 0) { 370 (void) ds_close(0); 371 progerr(pkg_gt(ERR_UNPACK)); 372 logerr(pkg_gt(MSG_OPEN), device, errno); 373 return (-1); 374 } 375 376 /* read the block again */ 377 if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) { 378 rpterr(); 379 progerr(pkg_gt(ERR_UNPACK)); 380 logerr(pkg_gt(MSG_TOC)); 381 (void) ds_close(0); 382 return (-1); 383 } 384 } 385 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)); 393 (void) ds_close(0); 394 return (1); 395 } 396 397 /* clear the new memory */ 398 (void) memset(ds_header + header_size, '\0', 399 BLK_SIZE); 400 401 402 /* read a logical block from the source device */ 403 if (read(ds_fd, ds_header + header_size, BLK_SIZE) != 404 BLK_SIZE) { 405 rpterr(); 406 progerr(pkg_gt(ERR_UNPACK)); 407 logerr(pkg_gt(MSG_TOC)); 408 (void) ds_close(0); 409 return (-1); 410 } else 411 header_size += BLK_SIZE; /* new size */ 412 } 413 414 /* 415 * remember rewind device for ds_close to rewind at 416 * close 417 */ 418 if (count >= 1) 419 ds_device = device; 420 ds_headsize = header_size; 421 422 } 423 424 pds_header = ds_header; 425 426 /* read datastream table of contents */ 427 ds_head = tail = (struct dstoc *)0; 428 ds_volcnt = 1; 429 430 while (ret = ds_gets(line, LSIZE)) { 431 if (strcmp(line, HDR_SUFFIX) == 0) 432 break; 433 if (!line[0] || line[0] == '#') 434 continue; 435 toc_pt = (struct dstoc *)calloc(1, sizeof (struct dstoc)); 436 if (!toc_pt) { 437 progerr(pkg_gt(ERR_UNPACK)); 438 logerr(pkg_gt(MSG_MEM)); 439 ecleanup(); 440 (void) free(ds_header); 441 return (-1); 442 } 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)); 448 free(toc_pt); 449 (void) free(ds_header); 450 ecleanup(); 451 return (-1); 452 } 453 if (tail) { 454 tail->next = toc_pt; 455 tail = toc_pt; 456 } else 457 ds_head = tail = toc_pt; 458 ds_volcnt += ds_volsum(toc_pt); 459 } 460 if (!ret) { 461 progerr(pkg_gt(ERR_UNPACK)); 462 logerr(pkg_gt(MSG_TOC)); 463 (void) free(ds_header); 464 return (-1); 465 } 466 (void) sighold(SIGINT); 467 (void) sigrelse(SIGINT); 468 if (!ds_head) { 469 progerr(pkg_gt(ERR_UNPACK)); 470 logerr(pkg_gt(MSG_EMPTY)); 471 (void) free(ds_header); 472 return (-1); 473 } 474 /* this could break, thanks to cpio command limit */ 475 (void) snprintf(cmd, sizeof (cmd), "%s -icdumD -C %d", 476 CPIOPROC, (int)BLK_SIZE); 477 n = 0; 478 for (i = 0; pkg[i]; i++) { 479 if (strcmp(pkg[i], "all") == 0) 480 continue; 481 if (n == 0) { 482 (void) strlcat(cmd, " ", CMDSIZ); 483 n = 1; 484 } 485 (void) strlcat(cmd, pkg[i], CMDSIZ); 486 (void) strlcat(cmd, "'/*' ", CMDSIZ); 487 (void) strlcat(cmd, " ", CMDSIZ); 488 } 489 490 if (n = esystem(cmd, ds_fd, -1)) { 491 rpterr(); 492 progerr(pkg_gt(ERR_UNPACK)); 493 logerr(pkg_gt(MSG_CMDFAIL), cmd, n); 494 (void) free(ds_header); 495 return (-1); 496 } 497 498 ds_toc = ds_head; 499 ds_totread = 0; 500 ds_volno = 1; 501 return (0); 502 } 503 504 int 505 ds_findpkg(char *device, char *pkg) 506 { 507 char *pkglist[2]; 508 int nskip, ods_volpart; 509 510 if (ds_head == NULL) { 511 pkglist[0] = pkg; 512 pkglist[1] = NULL; 513 if (ds_init(device, pkglist, NULL)) 514 return (-1); 515 } 516 517 if (!pkg || pkgnmchk(pkg, "all", 0)) { 518 progerr(pkg_gt(ERR_UNPACK)); 519 logerr(pkg_gt(MSG_PKGNAME)); 520 return (-1); 521 } 522 523 nskip = 0; 524 ds_volno = 1; 525 ds_volpart = 0; 526 ds_toc = ds_head; 527 while (ds_toc) { 528 if (strcmp(ds_toc->pkg, pkg) == 0) 529 break; 530 nskip += ds_toc->nparts; 531 ds_volno += ds_volsum(ds_toc); 532 ds_toc = ds_toc->next; 533 } 534 if (!ds_toc) { 535 progerr(pkg_gt(ERR_UNPACK)); 536 logerr(pkg_gt(MSG_NOPKG), pkg); 537 return (-1); 538 } 539 540 ds_pkginit(); 541 ds_skippart = 0; 542 if (ds_curpartcnt > 0) { 543 ods_volpart = ds_volpart; 544 /* 545 * skip past archives belonging to last package on current 546 * volume 547 */ 548 if (ds_volpart > 0 && ds_getnextvol(device)) 549 return (-1); 550 ds_totread = nskip - ods_volpart; 551 if (ds_skip(device, ods_volpart)) 552 return (-1); 553 } else if (ds_curpartcnt < 0) { 554 if (ds_skip(device, nskip - ds_totread)) 555 return (-1); 556 } else 557 ds_totread = nskip; 558 ds_read = 0; 559 return (ds_nparts); 560 } 561 562 /* 563 * Get datastream part 564 * Call for first part should be preceded by 565 * call to ds_findpkg 566 */ 567 568 int 569 ds_getpkg(char *device, int n, char *dstdir) 570 { 571 struct statvfs64 svfsb; 572 u_longlong_t free_blocks; 573 574 if (ds_read >= ds_nparts) 575 return (2); 576 577 if (ds_read == n) 578 return (0); 579 else if ((ds_read > n) || (n > ds_nparts)) 580 return (2); 581 582 if (ds_maxsiz > 0) { 583 if (statvfs64(".", &svfsb)) { 584 progerr(pkg_gt(ERR_UNPACK)); 585 logerr(pkg_gt(MSG_STATFS), errno); 586 return (-1); 587 } 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); 594 return (-1); 595 } 596 } 597 return (ds_next(device, dstdir)); 598 } 599 600 static int 601 ds_getnextvol(char *device) 602 { 603 char prompt[128]; 604 int n; 605 606 if (ds_close(0)) 607 return (-1); 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, 0, prompt)) 612 return (n); 613 if ((ds_fd = open(device, O_RDONLY)) < 0) 614 return (-1); 615 if (ds_ginit(device) < 0) { 616 (void) ds_close(0); 617 return (-1); 618 } 619 ds_volpart = 0; 620 return (0); 621 } 622 623 /* 624 * called by ds_findpkg to skip past archives for unwanted packages 625 * in current volume 626 */ 627 static int 628 ds_skip(char *device, int nskip) 629 { 630 char cmd[CMDSIZ]; 631 int n, onskip = nskip; 632 633 while (nskip--) { 634 /* skip this one */ 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)) { 638 rpterr(); 639 progerr(pkg_gt(ERR_UNPACK)); 640 logerr(pkg_gt(MSG_CMDFAIL), cmd, n); 641 nskip = onskip; 642 if (ds_volno == 1 || ds_volpart > 0) 643 return (n); 644 if (n = ds_getnextvol(device)) 645 return (n); 646 } 647 } 648 ds_totread += onskip; 649 ds_volpart = onskip; 650 ds_skippart = onskip; 651 return (0); 652 } 653 654 /* skip to end of package if necessary */ 655 void 656 ds_skiptoend(char *device) 657 { 658 if (ds_read < ds_nparts && ds_curpartcnt < 0) 659 (void) ds_skip(device, ds_nparts - ds_read); 660 } 661 662 int 663 ds_next(char *device, char *instdir) 664 { 665 char cmd[CMDSIZ], tmpvol[128]; 666 int nparts, n, index; 667 668 /*CONSTCOND*/ 669 while (1) { 670 if (ds_read + 1 > ds_curpartcnt && ds_curpartcnt >= 0) { 671 ds_volno++; 672 if (n = ds_getnextvol(device)) 673 return (n); 674 (void) sscanf(ds_volnos, "%d %[ 0-9]", &index, tmpvol); 675 (void) strcpy(ds_volnos, tmpvol); 676 ds_curpartcnt += index; 677 } 678 (void) snprintf(cmd, sizeof (cmd), "%s -icdumD -C %d", 679 CPIOPROC, (int)BLK_SIZE); 680 if (n = esystem(cmd, ds_fd, -1)) { 681 rpterr(); 682 progerr(pkg_gt(ERR_UNPACK)); 683 logerr(pkg_gt(MSG_CMDFAIL), cmd, n); 684 } 685 if (ds_read == 0) 686 nparts = 0; 687 else 688 nparts = ds_toc->nparts; 689 if (n || (n = ckvolseq(instdir, ds_read + 1, nparts))) { 690 if (ds_volno == 1 || ds_volpart > ds_skippart) 691 return (-1); 692 693 if (n = ds_getnextvol(device)) 694 return (n); 695 continue; 696 } 697 ds_read++; 698 ds_totread++; 699 ds_volpart++; 700 701 return (0); 702 } 703 /*NOTREACHED*/ 704 } 705 706 /* 707 * ds_ginit: Determine the device being accessed, set the buffer size, 708 * and perform any device specific initialization. 709 */ 710 711 int 712 ds_ginit(char *device) 713 { 714 int oflag; 715 char *pbufsize, cmd[CMDSIZ]; 716 int fd2, fd; 717 718 if ((pbufsize = devattr(device, "bufsize")) != NULL) { 719 ds_bufsize = atoi(pbufsize); 720 (void) free(pbufsize); 721 } else 722 ds_bufsize = BLK_SIZE; 723 oflag = fcntl(ds_fd, F_GETFL, 0); 724 725 if (ds_bufsize > BLK_SIZE) { 726 if (oflag & O_WRONLY) 727 fd = 1; 728 else 729 fd = 0; 730 fd2 = fcntl(fd, F_DUPFD, fd); 731 (void) close(fd); 732 (void) fcntl(ds_fd, F_DUPFD, fd); 733 if (fd) 734 (void) snprintf(cmd, sizeof (cmd), 735 "%s obs=%d 2>/dev/null", DDPROC, ds_bufsize); 736 else 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); 742 return (-1); 743 } 744 (void) close(fd); 745 (void) fcntl(fd2, F_DUPFD, fd); 746 (void) close(fd2); 747 ds_realfd = ds_fd; 748 ds_fd = fileno(ds_pp); 749 } 750 return (ds_bufsize); 751 } 752 753 int 754 ds_close(int pkgendflg) 755 { 756 int n, ret = 0; 757 758 if (pkgendflg) { 759 if (ds_header) 760 (void) free(ds_header); 761 ds_header = (char *)NULL; 762 ds_totread = 0; 763 } 764 765 if (ds_pp) { 766 (void) pclose(ds_pp); 767 ds_pp = 0; 768 (void) close(ds_realfd); 769 ds_realfd = -1; 770 ds_fd = -1; 771 } else if (ds_fd >= 0) { 772 (void) close(ds_fd); 773 ds_fd = -1; 774 } 775 776 if (ds_device) { 777 /* rewind device */ 778 if ((n = open(ds_device, 0)) >= 0) 779 (void) close(n); 780 ds_device = NULL; 781 } 782 return (ret); 783 } 784