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 <errno.h> 38 #include <stdarg.h> 39 #include <limits.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 #include <fcntl.h> 43 #include <ctype.h> 44 #include <string.h> 45 #include <sys/types.h> 46 #include <sys/param.h> 47 #include <sys/stat.h> 48 #include <sys/statvfs.h> 49 #include <sys/sysmacros.h> 50 #include <dirent.h> 51 #include <signal.h> 52 #include <devmgmt.h> 53 #include <note.h> 54 #include "pkginfo.h" 55 #include "pkgstrct.h" 56 #include "pkgtrans.h" 57 #include "pkgdev.h" 58 #include "pkglib.h" 59 #include "pkglibmsgs.h" 60 #include "pkglocale.h" 61 62 extern char *pkgdir; /* pkgparam.c */ 63 64 /* libadm.a */ 65 extern char *devattr(char *device, char *attribute); 66 extern char *fpkginst(char *pkg, ...); 67 extern int fpkginfo(struct pkginfo *info, char *pkginst); 68 extern int getvol(char *device, char *label, int options, char *prompt); 69 extern int _getvol(char *device, char *label, int options, char *prompt, 70 char *norewind); 71 72 /* dstream.c */ 73 extern int ds_ginit(char *device); 74 extern int ds_close(int pkgendflg); 75 76 #define CPIOPROC "/usr/bin/cpio" 77 78 #define CMDSIZE 512 /* command block size */ 79 80 #define BLK_SIZE 512 /* size of logical block */ 81 82 #define ENTRY_MAX 256 /* max size of entry for cpio cmd or header */ 83 84 #define PKGINFO "pkginfo" 85 #define PKGMAP "pkgmap" 86 #define MAP_STAT_SIZE 60 /* 1st line of pkgmap (3 numbers & a : */ 87 88 #define INSTALL "install" 89 #define RELOC "reloc" 90 #define ROOT "root" 91 #define ARCHIVE "archive" 92 93 static struct pkgdev srcdev, dstdev; 94 static char *tmpdir; 95 static char *tmppath; 96 static char *tmpsymdir = NULL; 97 static char dstinst[NON_ABI_NAMELNGTH]; 98 static char *ids_name, *ods_name; 99 static int ds_volcnt; 100 static int ds_volno; 101 static int compressedsize, has_comp_size; 102 103 static void (*sigintHandler)(); 104 static void (*sighupHandler)(); 105 static void cleanup(void); 106 static void sigtrap(int signo); 107 static int rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize); 108 109 static int cat_and_count(struct dm_buf *, char *); 110 111 static int ckoverwrite(char *dir, char *inst, int options); 112 static int pkgxfer(char *srcinst, int options); 113 static int wdsheader(struct dm_buf *, char *device, char **pkg); 114 static struct dm_buf *genheader(char *, char **); 115 116 extern int ds_fd; /* open file descriptor for data stream WHERE? */ 117 118 static char *root_names[] = { 119 "root", 120 "root.cpio", 121 "root.Z", 122 "root.cpio.Z", 123 0 124 }; 125 126 static char *reloc_names[] = { 127 "reloc", 128 "reloc.cpio", 129 "reloc.Z", 130 "reloc.cpio.Z", 131 0 132 }; 133 134 static int signal_received = 0; 135 136 char **xpkg; /* array of transferred packages */ 137 int nxpkg; 138 139 static char *allpkg[] = { 140 "all", 141 NULL 142 }; 143 144 static struct dm_buf hdrbuf; 145 static char *pinput, *nextpinput; 146 147 int 148 pkghead(char *device) 149 { 150 char *pt; 151 int n; 152 153 cleanup(); 154 155 156 if (device == NULL) 157 return (0); 158 else if ((device[0] == '/') && !isdir(device)) { 159 pkgdir = device; 160 return (0); 161 } else if ((pt = devattr(device, "pathname")) != NULL && !isdir(pt)) { 162 pkgdir = pt; 163 return (0); 164 } 165 166 /* check for datastream */ 167 if (n = pkgtrans(device, (char *)0, allpkg, PT_SILENT|PT_INFO_ONLY)) { 168 cleanup(); 169 return (n); 170 } 171 /* pkgtrans has set pkgdir */ 172 return (0); 173 } 174 175 static char * 176 mgets(char *buf, int size) 177 { 178 nextpinput = strchr(pinput, '\n'); 179 if (nextpinput == NULL) 180 return (0); 181 *nextpinput = '\0'; 182 if ((int)strlen(pinput) > size) 183 return (0); 184 (void) strncpy(buf, pinput, strlen(pinput)); 185 buf[strlen(pinput)] = '\0'; 186 pinput = nextpinput + 1; 187 return (buf); 188 } 189 /* 190 * Here we construct the package size summaries for the headers. The 191 * pkgmap file associated with fp must be rewound to the beginning of the 192 * file. Note that we read three values from pkgmap first line in order 193 * to get the *actual* size if this package is compressed. 194 * This returns 195 * 0 : error 196 * 2 : not a compressed package 197 * 3 : compressed package 198 * and sets has_comp_size to indicate whether or not this is a compressed 199 * package. 200 */ 201 static int 202 rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize) 203 { 204 int n; 205 char line_buffer[MAP_STAT_SIZE]; 206 207 /* First read the null terminated first line */ 208 if (fgets(line_buffer, MAP_STAT_SIZE, fp) == NULL) { 209 progerr(pkg_gt(ERR_TRANSFER)); 210 logerr(pkg_gt(MSG_NOSIZE)); 211 (void) fclose(fp); 212 ecleanup(); 213 return (0); 214 } 215 216 n = sscanf(line_buffer, ": %d %d %d", npts, maxpsz, cmpsize); 217 218 if (n == 3) /* A valid compressed package entry */ 219 has_comp_size = 1; 220 else if (n == 2) /* A valid standard package entry */ 221 has_comp_size = 0; 222 else { /* invalid entry */ 223 progerr(pkg_gt(ERR_TRANSFER)); 224 logerr(pkg_gt(MSG_NOSIZE)); 225 (void) fclose(fp); 226 ecleanup(); 227 return (0); 228 } 229 230 return (n); 231 } 232 233 /* will return 0, 1, 3, or 99 */ 234 static int 235 _pkgtrans(char *device1, char *device2, char **pkg, int options) 236 { 237 char *src, *dst; 238 int errflg, i, n; 239 struct dm_buf *hdr; 240 241 if (signal_received > 0) { 242 return (1); 243 } 244 245 /* transfer spool to appropriate device */ 246 if (devtype(device1, &srcdev)) { 247 progerr(pkg_gt(ERR_TRANSFER)); 248 logerr(pkg_gt(MSG_BADDEV), device1); 249 return (1); 250 } 251 srcdev.rdonly++; 252 253 /* check for datastream */ 254 ids_name = NULL; 255 if (srcdev.bdevice) { 256 if (n = _getvol(srcdev.bdevice, NULL, 0, 257 pkg_gt("Insert %v into %p."), srcdev.norewind)) { 258 cleanup(); 259 if (n == 3) 260 return (3); 261 progerr(pkg_gt(ERR_TRANSFER)); 262 logerr(pkg_gt(MSG_GETVOL)); 263 return (1); 264 } 265 if (ds_readbuf(srcdev.cdevice)) 266 ids_name = srcdev.cdevice; 267 } 268 269 if (srcdev.cdevice && !srcdev.bdevice) 270 ids_name = srcdev.cdevice; 271 else if (srcdev.pathname) { 272 ids_name = srcdev.pathname; 273 if (access(ids_name, 0) == -1) { 274 progerr(ERR_TRANSFER); 275 logerr(pkg_gt(MSG_GETVOL)); 276 return (1); 277 } 278 } 279 280 if (!ids_name && device2 == (char *)0) { 281 if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) { 282 cleanup(); 283 return (n); 284 } 285 if (srcdev.mount && *srcdev.mount) 286 pkgdir = strdup(srcdev.mount); 287 return (0); 288 } 289 290 if (ids_name && device2 == (char *)0) { 291 tmppath = tmpnam(NULL); 292 tmppath = strdup(tmppath); 293 if (tmppath == NULL) { 294 progerr(pkg_gt(ERR_TRANSFER)); 295 logerr(pkg_gt(MSG_MEM)); 296 return (1); 297 } 298 if (mkdir(tmppath, 0755)) { 299 progerr(pkg_gt(ERR_TRANSFER)); 300 logerr(pkg_gt(MSG_MKDIR), tmppath); 301 return (1); 302 } 303 device2 = tmppath; 304 } 305 306 if (devtype(device2, &dstdev)) { 307 progerr(pkg_gt(ERR_TRANSFER)); 308 logerr(pkg_gt(MSG_BADDEV), device2); 309 return (1); 310 } 311 312 if ((srcdev.cdevice && dstdev.cdevice) && 313 strcmp(srcdev.cdevice, dstdev.cdevice) == 0) { 314 progerr(pkg_gt(ERR_TRANSFER)); 315 logerr(pkg_gt(MSG_SAMEDEV)); 316 return (1); 317 } 318 319 ods_name = NULL; 320 if (dstdev.cdevice && !dstdev.bdevice || dstdev.pathname) 321 options |= PT_ODTSTREAM; 322 323 if (options & PT_ODTSTREAM) { 324 if (!((ods_name = dstdev.cdevice) != NULL || 325 (ods_name = dstdev.pathname) != NULL)) { 326 progerr(pkg_gt(ERR_TRANSFER)); 327 logerr(pkg_gt(MSG_BADDEV), device2); 328 return (1); 329 } 330 if (ids_name) { 331 progerr(pkg_gt(ERR_TRANSFER)); 332 logerr(pkg_gt(MSG_TWODSTREAM)); 333 return (1); 334 } 335 } 336 337 if ((srcdev.dirname && dstdev.dirname) && 338 strcmp(srcdev.dirname, dstdev.dirname) == 0) { 339 progerr(pkg_gt(ERR_TRANSFER)); 340 logerr(pkg_gt(MSG_SAMEDEV)); 341 return (1); 342 } 343 344 if ((srcdev.pathname && dstdev.pathname) && 345 strcmp(srcdev.pathname, dstdev.pathname) == 0) { 346 progerr(pkg_gt(ERR_TRANSFER)); 347 logerr(pkg_gt(MSG_SAMEDEV)); 348 return (1); 349 } 350 351 if (signal_received > 0) { 352 return (1); 353 } 354 355 if (ids_name) { 356 if (srcdev.cdevice && !srcdev.bdevice && 357 (n = _getvol(srcdev.cdevice, NULL, 0, NULL, 358 srcdev.norewind))) { 359 cleanup(); 360 if (n == 3) 361 return (3); 362 progerr(pkg_gt(ERR_TRANSFER)); 363 logerr(pkg_gt(MSG_GETVOL)); 364 return (1); 365 } 366 if (srcdev.dirname = tmpnam(NULL)) 367 tmpdir = srcdev.dirname = strdup(srcdev.dirname); 368 369 if ((srcdev.dirname == NULL) || mkdir(srcdev.dirname, 0755) || 370 chdir(srcdev.dirname)) { 371 progerr(pkg_gt(ERR_TRANSFER)); 372 logerr(pkg_gt(MSG_NOTEMP), srcdev.dirname); 373 cleanup(); 374 return (1); 375 } 376 if (ds_init(ids_name, pkg, srcdev.norewind)) { 377 cleanup(); 378 return (1); 379 } 380 } else if (srcdev.mount) { 381 if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) { 382 cleanup(); 383 return (n); 384 } 385 } 386 387 src = srcdev.dirname; 388 dst = dstdev.dirname; 389 390 if (chdir(src)) { 391 progerr(pkg_gt(ERR_TRANSFER)); 392 logerr(pkg_gt(MSG_CHDIR), src); 393 cleanup(); 394 return (1); 395 } 396 397 if (signal_received > 0) { 398 return (1); 399 } 400 401 xpkg = pkg = gpkglist(src, pkg, NULL); 402 if (!pkg) { 403 progerr(pkg_gt(ERR_TRANSFER)); 404 logerr(pkg_gt(MSG_NOPKGS), src); 405 cleanup(); 406 return (1); 407 } 408 409 for (nxpkg = 0; pkg[nxpkg]; /* void */) { 410 nxpkg++; /* count */ 411 } 412 413 if (ids_name) { 414 ds_order(pkg); /* order requests */ 415 } 416 417 if (signal_received > 0) { 418 return (1); 419 } 420 421 if (options & PT_ODTSTREAM) { 422 char line[128]; 423 424 if (!dstdev.pathname && 425 (n = _getvol(ods_name, NULL, DM_FORMAT, NULL, 426 dstdev.norewind))) { 427 cleanup(); 428 if (n == 3) 429 return (3); 430 progerr(pkg_gt(ERR_TRANSFER)); 431 logerr(pkg_gt(MSG_GETVOL)); 432 return (1); 433 } 434 if ((hdr = genheader(src, pkg)) == NULL) { 435 cleanup(); 436 return (1); 437 } 438 439 /* write out header to stream */ 440 if (wdsheader(hdr, ods_name, pkg)) { 441 cleanup(); 442 return (1); 443 } 444 445 ds_volno = 1; /* number of volumes in datastream */ 446 pinput = hdrbuf.text_buffer; 447 /* skip past first line in header */ 448 (void) mgets(line, 128); 449 } 450 451 if (signal_received > 0) { 452 return (1); 453 } 454 455 errflg = 0; 456 457 for (i = 0; pkg[i]; i++) { 458 459 if (signal_received > 0) { 460 return (1); 461 } 462 463 if (!(options & PT_ODTSTREAM) && dstdev.mount) { 464 if (n = pkgmount(&dstdev, NULL, 0, 0, 1)) { 465 cleanup(); 466 return (n); 467 } 468 } 469 if (errflg = pkgxfer(pkg[i], options)) { 470 pkg[i] = NULL; 471 if ((options & PT_ODTSTREAM) || (errflg != 2)) 472 break; 473 } else if (strcmp(dstinst, pkg[i])) 474 pkg[i] = strdup(dstinst); 475 } 476 477 if (!(options & PT_ODTSTREAM) && dst) { 478 pkgdir = strdup(dst); 479 } 480 481 /* 482 * No cleanup of temporary directories created in this 483 * function is done here. The calling function must do 484 * the cleanup. 485 */ 486 487 return (signal_received > 0 ? 1 : errflg); 488 } 489 490 int 491 pkgtrans(char *device1, char *device2, char **pkg, int options) 492 { 493 int r; 494 struct sigaction nact; 495 struct sigaction oact; 496 497 /* 498 * setup signal handlers for SIGINT and SIGHUP and release hold 499 */ 500 501 /* hold SIGINT/SIGHUP interrupts */ 502 503 (void) sighold(SIGHUP); 504 (void) sighold(SIGINT); 505 506 /* hook SIGINT to sigtrap */ 507 508 nact.sa_handler = sigtrap; 509 nact.sa_flags = SA_RESTART; 510 (void) sigemptyset(&nact.sa_mask); 511 512 if (sigaction(SIGINT, &nact, &oact) < 0) { 513 sigintHandler = SIG_DFL; 514 } else { 515 sigintHandler = oact.sa_handler; 516 } 517 518 /* hook SIGHUP to sigtrap */ 519 520 nact.sa_handler = sigtrap; 521 nact.sa_flags = SA_RESTART; 522 (void) sigemptyset(&nact.sa_mask); 523 524 if (sigaction(SIGHUP, &nact, &oact) < 0) { 525 sighupHandler = SIG_DFL; 526 } else { 527 sighupHandler = oact.sa_handler; 528 } 529 530 /* reset signal received count */ 531 532 signal_received = 0; 533 534 /* release hold on signals */ 535 536 (void) sigrelse(SIGHUP); 537 (void) sigrelse(SIGINT); 538 539 /* 540 * perform the package translation 541 */ 542 543 r = _pkgtrans(device1, device2, pkg, options); 544 545 /* 546 * reset signal handlers 547 */ 548 549 /* hold SIGINT/SIGHUP interrupts */ 550 551 (void) sighold(SIGHUP); 552 (void) sighold(SIGINT); 553 554 /* reset SIGINT */ 555 556 nact.sa_handler = sigintHandler; 557 nact.sa_flags = SA_RESTART; 558 (void) sigemptyset(&nact.sa_mask); 559 560 (void) sigaction(SIGINT, &nact, (struct sigaction *)NULL); 561 562 /* reset SIGHUP */ 563 564 nact.sa_handler = sighupHandler; 565 nact.sa_flags = SA_RESTART; 566 (void) sigemptyset(&nact.sa_mask); 567 568 (void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL); 569 570 /* if signal received and pkgtrans returned error, call cleanup */ 571 572 if (signal_received > 0) { 573 if (r != 0) { 574 cleanup(); 575 } 576 (void) kill(getpid(), SIGINT); 577 } 578 579 /* release hold on signals */ 580 581 (void) sigrelse(SIGHUP); 582 (void) sigrelse(SIGINT); 583 584 return (r); 585 } 586 587 /* 588 * This function concatenates append to the text described in the buf_ctrl 589 * structure. This code modifies data in this structure and handles all 590 * allocation issues. It returns '0' if everything was successful and '1' 591 * if not. 592 */ 593 static int 594 cat_and_count(struct dm_buf *buf_ctrl, char *append) 595 { 596 597 /* keep allocating until we have enough room to hold string */ 598 while ((buf_ctrl->offset + (int)strlen(append)) 599 >= buf_ctrl->allocation) { 600 /* reallocate (and maybe move) text buffer */ 601 if ((buf_ctrl->text_buffer = 602 (char *)realloc(buf_ctrl->text_buffer, 603 buf_ctrl->allocation + BLK_SIZE)) == NULL) { 604 progerr(pkg_gt(ERR_TRANSFER)); 605 logerr(pkg_gt(MSG_MEM)); 606 free(buf_ctrl->text_buffer); 607 return (1); 608 } 609 610 /* clear the new memory */ 611 (void) memset(buf_ctrl->text_buffer + 612 buf_ctrl->allocation, '\0', BLK_SIZE); 613 614 /* adjust total allocation */ 615 buf_ctrl->allocation += BLK_SIZE; 616 } 617 618 /* append new string to end of buffer */ 619 while (*append) { 620 *(buf_ctrl->text_buffer + buf_ctrl->offset) = *append++; 621 (buf_ctrl->offset)++; 622 } 623 624 return (0); 625 } 626 627 static struct dm_buf * 628 genheader(char *src, char **pkg) 629 { 630 631 FILE *fp; 632 char path[MAXPATHLEN], tmp_entry[ENTRY_MAX]; 633 int i, n, nparts, maxpsize; 634 int partcnt; 635 long totsize; 636 struct stat statbuf; 637 638 if ((hdrbuf.text_buffer = (char *)malloc(BLK_SIZE)) == NULL) { 639 progerr(pkg_gt(ERR_TRANSFER)); 640 logerr(pkg_gt(MSG_MEM)); 641 return (NULL); 642 } 643 644 /* clear the new memory */ 645 (void) memset(hdrbuf.text_buffer, '\0', BLK_SIZE); 646 647 /* set up the buffer control structure for the header */ 648 hdrbuf.offset = 0; 649 hdrbuf.allocation = BLK_SIZE; 650 651 (void) cat_and_count(&hdrbuf, HDR_PREFIX); 652 (void) cat_and_count(&hdrbuf, "\n"); 653 654 nparts = maxpsize = 0; 655 656 totsize = 0; 657 for (i = 0; pkg[i]; i++) { 658 (void) snprintf(path, MAXPATHLEN, "%s/%s/%s", 659 src, pkg[i], PKGINFO); 660 if (stat(path, &statbuf) < 0) { 661 progerr(pkg_gt(ERR_TRANSFER)); 662 logerr(pkg_gt(MSG_BADPKGINFO)); 663 ecleanup(); 664 return (NULL); 665 } 666 totsize += statbuf.st_size/BLK_SIZE + 1; 667 } 668 669 /* 670 * totsize contains number of blocks used by the pkginfo files 671 */ 672 totsize += i/4 + 1; 673 if (dstdev.capacity && totsize > dstdev.capacity) { 674 progerr(pkg_gt(ERR_TRANSFER)); 675 logerr(pkg_gt(MSG_NOSPACE), totsize, dstdev.capacity); 676 ecleanup(); 677 return (NULL); 678 } 679 680 ds_volcnt = 1; 681 for (i = 0; pkg[i]; i++) { 682 partcnt = 0; 683 (void) snprintf(path, MAXPATHLEN, "%s/%s/%s", 684 src, pkg[i], PKGMAP); 685 if ((fp = fopen(path, "r")) == NULL) { 686 progerr(pkg_gt(ERR_TRANSFER)); 687 logerr(pkg_gt(MSG_NOPKGMAP), pkg[i]); 688 ecleanup(); 689 return (NULL); 690 } 691 692 /* Evaluate the first entry in pkgmap */ 693 n = rd_map_size(fp, &nparts, &maxpsize, &compressedsize); 694 695 if (n == 3) /* It's a compressed package */ 696 /* The header needs the *real* size */ 697 maxpsize = compressedsize; 698 else if (n == 0) /* pkgmap is corrupt */ 699 return (NULL); 700 701 if (dstdev.capacity && maxpsize > dstdev.capacity) { 702 progerr(pkg_gt(ERR_TRANSFER)); 703 logerr(pkg_gt(MSG_NOSPACE), (long)maxpsize, 704 dstdev.capacity); 705 (void) fclose(fp); 706 ecleanup(); 707 return (NULL); 708 } 709 710 /* add pkg name, number of parts and the max part size */ 711 if (snprintf(tmp_entry, ENTRY_MAX, "%s %d %d", 712 pkg[i], nparts, maxpsize) >= ENTRY_MAX) { 713 progerr(pkg_gt(ERR_TRANSFER)); 714 logerr(pkg_gt(ERR_MEM)); 715 (void) fclose(fp); 716 ecleanup(); 717 return (NULL); 718 } 719 if (cat_and_count(&hdrbuf, tmp_entry)) { 720 progerr(pkg_gt(ERR_TRANSFER)); 721 logerr(pkg_gt(MSG_MEM)); 722 (void) fclose(fp); 723 ecleanup(); 724 return (NULL); 725 } 726 727 totsize += nparts * maxpsize; 728 if (dstdev.capacity && dstdev.capacity < totsize) { 729 int lastpartcnt = 0; 730 731 if (totsize) 732 totsize -= nparts * maxpsize; 733 while (partcnt < nparts) { 734 while (totsize <= dstdev.capacity && 735 partcnt <= nparts) { 736 totsize += maxpsize; 737 partcnt++; 738 } 739 /* partcnt == 0 means skip to next volume */ 740 if (partcnt) 741 partcnt--; 742 (void) snprintf(tmp_entry, ENTRY_MAX, 743 " %d", partcnt - lastpartcnt); 744 if (cat_and_count(&hdrbuf, tmp_entry)) { 745 progerr(pkg_gt(ERR_TRANSFER)); 746 logerr(pkg_gt(MSG_MEM)); 747 (void) fclose(fp); 748 ecleanup(); 749 return (NULL); 750 } 751 ds_volcnt++; 752 totsize = 0; 753 lastpartcnt = partcnt; 754 } 755 /* first parts/volume number does not count */ 756 ds_volcnt--; 757 } 758 759 if (cat_and_count(&hdrbuf, "\n")) { 760 progerr(pkg_gt(ERR_TRANSFER)); 761 logerr(pkg_gt(MSG_MEM)); 762 (void) fclose(fp); 763 ecleanup(); 764 return (NULL); 765 } 766 767 (void) fclose(fp); 768 } 769 770 if (cat_and_count(&hdrbuf, HDR_SUFFIX) || 771 cat_and_count(&hdrbuf, "\n")) { 772 progerr(pkg_gt(ERR_TRANSFER)); 773 logerr(pkg_gt(MSG_MEM)); 774 (void) fclose(fp); 775 ecleanup(); 776 return (NULL); 777 } 778 return (&hdrbuf); 779 } 780 781 static int 782 wdsheader(struct dm_buf *hdr, char *device, char **pkg) 783 { 784 char tmp_entry[ENTRY_MAX], tmp_file[L_tmpnam+1]; 785 int i, n; 786 int list_fd; 787 int block_cnt; 788 789 (void) ds_close(0); 790 if (dstdev.pathname) 791 ds_fd = creat(device, 0644); 792 else 793 ds_fd = open(device, 1); 794 795 if (ds_fd < 0) { 796 progerr(pkg_gt(ERR_TRANSFER)); 797 logerr(pkg_gt(MSG_OPEN), device, errno); 798 return (1); 799 } 800 801 if (ds_ginit(device) < 0) { 802 progerr(pkg_gt(ERR_TRANSFER)); 803 logerr(pkg_gt(MSG_OPEN), device, errno); 804 (void) ds_close(0); 805 return (1); 806 } 807 808 /* 809 * The loop below assures compatibility with tapes that don't 810 * have a block size (e.g.: Exabyte) by forcing EOR at the end 811 * of each 512 bytes. 812 */ 813 for (block_cnt = 0; block_cnt < hdr->allocation; 814 block_cnt += BLK_SIZE) { 815 (void) write(ds_fd, (hdr->text_buffer + block_cnt), BLK_SIZE); 816 } 817 818 /* 819 * write the first cpio() archive to the datastream 820 * which should contain the pkginfo & pkgmap files 821 * for all packages 822 */ 823 (void) tmpnam(tmp_file); /* temporary file name */ 824 if ((list_fd = open(tmp_file, O_RDWR | O_CREAT, 0644)) == -1) { 825 progerr(pkg_gt(ERR_TRANSFER)); 826 logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); 827 return (1); 828 } 829 830 /* 831 * Create a cpio-compatible list of the requisite files in 832 * the temporary file. 833 */ 834 for (i = 0; pkg[i]; i++) { 835 register ssize_t entry_size; 836 837 /* 838 * Copy pkginfo and pkgmap filenames into the 839 * temporary string allowing for the first line 840 * as a special case. 841 */ 842 entry_size = sprintf(tmp_entry, 843 (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", 844 pkg[i], PKGINFO, pkg[i], PKGMAP); 845 846 if (write(list_fd, tmp_entry, 847 entry_size) != entry_size) { 848 progerr(pkg_gt(ERR_TRANSFER)); 849 logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); 850 (void) close(list_fd); 851 ecleanup(); 852 return (1); 853 } 854 } 855 856 (void) lseek(list_fd, 0, SEEK_SET); 857 858 (void) snprintf(tmp_entry, sizeof (tmp_entry), 859 "%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); 860 861 if (n = esystem(tmp_entry, list_fd, ds_fd)) { 862 rpterr(); 863 progerr(pkg_gt(ERR_TRANSFER)); 864 logerr(pkg_gt(MSG_CMDFAIL), tmp_entry, n); 865 (void) close(list_fd); 866 (void) unlink(tmp_file); 867 cleanup(); 868 return (1); 869 } 870 871 (void) close(list_fd); 872 (void) unlink(tmp_file); 873 874 return (0); 875 } 876 877 static int 878 ckoverwrite(char *dir, char *inst, int options) 879 { 880 char path[PATH_MAX]; 881 882 (void) snprintf(path, sizeof (path), "%s/%s", dir, inst); 883 if (access(path, 0) == 0) { 884 if (options & PT_OVERWRITE) 885 return (rrmdir(path)); 886 progerr(pkg_gt(ERR_TRANSFER)); 887 logerr(pkg_gt(MSG_EXISTS), path); 888 return (1); 889 } 890 return (0); 891 } 892 893 static int 894 pkgxfer(char *srcinst, int options) 895 { 896 int r; 897 struct pkginfo info; 898 FILE *fp, *pp; 899 char *pt, *src, *dst; 900 char dstdir[PATH_MAX], temp[PATH_MAX], srcdir[PATH_MAX]; 901 char cmd[CMDSIZE], pkgname[NON_ABI_NAMELNGTH]; 902 int i, n, part, nparts, maxpartsize, curpartcnt, iscomp; 903 char volnos[128], tmpvol[128]; 904 struct statvfs64 svfsb; 905 longlong_t free_blocks; 906 struct stat srcstat; 907 908 info.pkginst = NULL; /* required initialization */ 909 910 /* 911 * when this routine is entered, the first part of 912 * the package to transfer is already available in 913 * the directory indicated by 'src' --- unless the 914 * source device is a datstream, in which case only 915 * the pkginfo and pkgmap files are available in 'src' 916 */ 917 src = srcdev.dirname; 918 dst = dstdev.dirname; 919 920 if (!(options & PT_SILENT)) 921 (void) fprintf(stderr, pkg_gt(MSG_TRANSFER), srcinst); 922 (void) strlcpy(dstinst, srcinst, sizeof (dstinst)); 923 924 if (!(options & PT_ODTSTREAM)) { 925 /* destination is a (possibly mounted) directory */ 926 (void) snprintf(dstdir, sizeof (dstdir), 927 "%s/%s", dst, dstinst); 928 929 /* 930 * need to check destination directory to assure 931 * that we will not be duplicating a package which 932 * already resides there (though we are allowed to 933 * overwrite the same version) 934 */ 935 pkgdir = src; 936 if (fpkginfo(&info, srcinst)) { 937 progerr(pkg_gt(ERR_TRANSFER)); 938 logerr(pkg_gt(MSG_NOEXISTS), srcinst); 939 (void) fpkginfo(&info, NULL); 940 return (1); 941 } 942 pkgdir = dst; 943 944 (void) strlcpy(temp, srcinst, sizeof (temp)); 945 if (pt = strchr(temp, '.')) 946 *pt = '\0'; 947 (void) strlcat(temp, ".*", sizeof (temp)); 948 949 if (pt = fpkginst(temp, info.arch, info.version)) { 950 /* 951 * the same instance already exists, although 952 * its pkgid might be different 953 */ 954 if (options & PT_OVERWRITE) { 955 (void) strlcpy(dstinst, pt, sizeof (dstinst)); 956 (void) snprintf(dstdir, sizeof (dstdir), 957 "%s/%s", dst, dstinst); 958 } else { 959 progerr(pkg_gt(ERR_TRANSFER)); 960 logerr(pkg_gt(MSG_DUPVERS), srcinst); 961 (void) fpkginfo(&info, NULL); 962 (void) fpkginst(NULL); 963 return (2); 964 } 965 } else if (options & PT_RENAME) { 966 /* 967 * find next available instance by appending numbers 968 * to the package abbreviation until the instance 969 * does not exist in the destination directory 970 */ 971 if (pt = strchr(temp, '.')) 972 *pt = '\0'; 973 for (i = 2; (access(dstdir, 0) == 0); i++) { 974 (void) snprintf(dstinst, sizeof (dstinst), 975 "%s.%d", temp, i); 976 (void) snprintf(dstdir, sizeof (dstdir), 977 "%s/%s", dst, dstinst); 978 } 979 } else if (options & PT_OVERWRITE) { 980 /* 981 * we're allowed to overwrite, but there seems 982 * to be no valid package to overwrite, and we are 983 * not allowed to rename the destination, so act 984 * as if we weren't given permission to overwrite 985 * --- this keeps us from removing a destination 986 * instance which is named the same as the source 987 * instance, but really reflects a different pkg! 988 */ 989 options &= (~PT_OVERWRITE); 990 } 991 (void) fpkginfo(&info, NULL); 992 (void) fpkginst(NULL); 993 994 if (ckoverwrite(dst, dstinst, options)) 995 return (2); 996 997 if (isdir(dstdir) && mkdir(dstdir, 0755)) { 998 progerr(pkg_gt(ERR_TRANSFER)); 999 logerr(pkg_gt(MSG_MKDIR), dstdir); 1000 return (1); 1001 } 1002 1003 (void) snprintf(srcdir, sizeof (srcdir), 1004 "%s/%s", src, srcinst); 1005 if (stat(srcdir, &srcstat) != -1) { 1006 if (chmod(dstdir, (srcstat.st_mode & S_IAMB)) == -1) { 1007 progerr(pkg_gt(ERR_TRANSFER)); 1008 logerr(pkg_gt(MSG_CHMODDIR), dstdir); 1009 return (1); 1010 } 1011 } else { 1012 progerr(pkg_gt(ERR_TRANSFER)); 1013 logerr(pkg_gt(MSG_STATDIR), srcdir); 1014 return (1); 1015 } 1016 } 1017 1018 if (!(options & PT_SILENT) && strcmp(dstinst, srcinst)) 1019 (void) fprintf(stderr, pkg_gt(MSG_RENAME), dstinst); 1020 1021 (void) snprintf(srcdir, sizeof (srcdir), "%s/%s", src, srcinst); 1022 if (chdir(srcdir)) { 1023 progerr(pkg_gt(ERR_TRANSFER)); 1024 logerr(pkg_gt(MSG_CHDIR), srcdir); 1025 return (1); 1026 } 1027 1028 if (ids_name) { /* unpack the datatstream into a directory */ 1029 /* 1030 * transfer pkginfo & pkgmap first 1031 */ 1032 (void) snprintf(cmd, sizeof (cmd), 1033 "%s -pudm %s", CPIOPROC, dstdir); 1034 if ((pp = epopen(cmd, "w")) == NULL) { 1035 rpterr(); 1036 progerr(pkg_gt(ERR_TRANSFER)); 1037 logerr(pkg_gt(MSG_POPEN), cmd, errno); 1038 return (1); 1039 } 1040 (void) fprintf(pp, "%s\n%s\n", PKGINFO, PKGMAP); 1041 1042 (void) sighold(SIGINT); 1043 (void) sighold(SIGHUP); 1044 r = epclose(pp); 1045 (void) sigrelse(SIGINT); 1046 (void) sigrelse(SIGHUP); 1047 1048 if (r != 0) { 1049 rpterr(); 1050 progerr(pkg_gt(ERR_TRANSFER)); 1051 logerr(pkg_gt(MSG_PCLOSE), cmd, errno); 1052 return (1); 1053 } 1054 1055 if (options & PT_INFO_ONLY) 1056 return (0); /* don't transfer objects */ 1057 1058 if (chdir(dstdir)) { 1059 progerr(pkg_gt(ERR_TRANSFER)); 1060 logerr(pkg_gt(MSG_CHDIR), dstdir); 1061 return (1); 1062 } 1063 1064 /* 1065 * for each part of the package, use cpio() to 1066 * unpack the archive into the destination directory 1067 */ 1068 nparts = ds_findpkg(srcdev.cdevice, srcinst); 1069 if (nparts < 0) { 1070 progerr(pkg_gt(ERR_TRANSFER)); 1071 return (1); 1072 } 1073 for (part = 1; part <= nparts; /* void */) { 1074 if (ds_getpkg(srcdev.cdevice, part, dstdir)) { 1075 progerr(pkg_gt(ERR_TRANSFER)); 1076 return (1); 1077 } 1078 part++; 1079 if (dstdev.mount) { 1080 (void) chdir("/"); 1081 if (pkgumount(&dstdev)) 1082 return (1); 1083 if (part <= nparts) { 1084 if (n = pkgmount(&dstdev, NULL, part+1, 1085 nparts, 1)) 1086 return (n); 1087 if (ckoverwrite(dst, dstinst, options)) 1088 return (1); 1089 if (isdir(dstdir) && 1090 mkdir(dstdir, 0755)) { 1091 progerr( 1092 pkg_gt(ERR_TRANSFER)); 1093 logerr(pkg_gt(MSG_MKDIR), 1094 dstdir); 1095 return (1); 1096 } 1097 /* 1098 * since volume is removable, each part 1099 * must contain a duplicate of the 1100 * pkginfo file to properly identify the 1101 * volume 1102 */ 1103 if (chdir(srcdir)) { 1104 progerr( 1105 pkg_gt(ERR_TRANSFER)); 1106 logerr(pkg_gt(MSG_CHDIR), 1107 srcdir); 1108 return (1); 1109 } 1110 if ((pp = epopen(cmd, "w")) == NULL) { 1111 rpterr(); 1112 progerr( 1113 pkg_gt(ERR_TRANSFER)); 1114 logerr(pkg_gt(MSG_POPEN), 1115 cmd, errno); 1116 return (1); 1117 } 1118 (void) fprintf(pp, "pkginfo"); 1119 1120 (void) sighold(SIGINT); 1121 (void) sighold(SIGHUP); 1122 r = epclose(pp); 1123 (void) sigrelse(SIGINT); 1124 (void) sigrelse(SIGHUP); 1125 1126 if (r != 0) { 1127 rpterr(); 1128 progerr( 1129 pkg_gt(ERR_TRANSFER)); 1130 logerr(pkg_gt(MSG_PCLOSE), 1131 cmd, errno); 1132 return (1); 1133 } 1134 if (chdir(dstdir)) { 1135 progerr( 1136 pkg_gt(ERR_TRANSFER)); 1137 logerr(pkg_gt(MSG_CHDIR), 1138 dstdir); 1139 return (1); 1140 } 1141 } 1142 } 1143 } 1144 return (0); 1145 } 1146 1147 if ((fp = fopen(PKGMAP, "r")) == NULL) { 1148 progerr(pkg_gt(ERR_TRANSFER)); 1149 logerr(pkg_gt(MSG_NOPKGMAP), srcinst); 1150 return (1); 1151 } 1152 1153 nparts = 1; 1154 if (!rd_map_size(fp, &nparts, &maxpartsize, &compressedsize)) 1155 return (1); 1156 else 1157 (void) fclose(fp); 1158 1159 if (srcdev.mount) { 1160 if (ckvolseq(srcdir, 1, nparts)) { 1161 progerr(pkg_gt(ERR_TRANSFER)); 1162 logerr(pkg_gt(MSG_SEQUENCE)); 1163 return (1); 1164 } 1165 } 1166 1167 /* write each part of this package */ 1168 if (options & PT_ODTSTREAM) { 1169 char line[128]; 1170 (void) mgets(line, 128); 1171 curpartcnt = -1; 1172 /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 1173 if (sscanf(line, "%s %d %d %[ 0-9]", pkgname, &nparts, 1174 &maxpartsize, volnos) == 4) { 1175 (void) sscanf(volnos, 1176 "%d %[ 0-9]", &curpartcnt, tmpvol); 1177 (void) strlcpy(volnos, tmpvol, sizeof (volnos)); 1178 } 1179 } 1180 1181 for (part = 1; part <= nparts; /* void */) { 1182 if (curpartcnt == 0 && (options & PT_ODTSTREAM)) { 1183 char prompt[128]; 1184 int index; 1185 ds_volno++; 1186 (void) ds_close(0); 1187 (void) sprintf(prompt, 1188 pkg_gt("Insert %%v %d of %d into %%p"), 1189 ds_volno, ds_volcnt); 1190 if (n = getvol(ods_name, NULL, DM_FORMAT, prompt)) 1191 return (n); 1192 if ((ds_fd = open(dstdev.cdevice, O_WRONLY)) < 0) { 1193 progerr(pkg_gt(ERR_TRANSFER)); 1194 logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, 1195 errno); 1196 return (1); 1197 } 1198 if (ds_ginit(dstdev.cdevice) < 0) { 1199 progerr(pkg_gt(ERR_TRANSFER)); 1200 logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, 1201 errno); 1202 (void) ds_close(0); 1203 return (1); 1204 } 1205 1206 (void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol); 1207 (void) strlcpy(volnos, tmpvol, sizeof (volnos)); 1208 curpartcnt += index; 1209 } 1210 1211 if (options & PT_INFO_ONLY) 1212 nparts = 0; 1213 1214 if (part == 1) { 1215 (void) snprintf(cmd, sizeof (cmd), 1216 "find %s %s", PKGINFO, PKGMAP); 1217 if (nparts && (isdir(INSTALL) == 0)) { 1218 (void) strlcat(cmd, " ", sizeof (cmd)); 1219 (void) strlcat(cmd, INSTALL, sizeof (cmd)); 1220 } 1221 } else 1222 (void) snprintf(cmd, sizeof (cmd), "find %s", PKGINFO); 1223 1224 if (nparts > 1) { 1225 (void) snprintf(temp, sizeof (temp), 1226 "%s.%d", RELOC, part); 1227 if (iscpio(temp, &iscomp) || isdir(temp) == 0) { 1228 (void) strlcat(cmd, " ", sizeof (cmd)); 1229 (void) strlcat(cmd, temp, sizeof (cmd)); 1230 } 1231 (void) snprintf(temp, sizeof (temp), 1232 "%s.%d", ROOT, part); 1233 if (iscpio(temp, &iscomp) || isdir(temp) == 0) { 1234 (void) strlcat(cmd, " ", sizeof (cmd)); 1235 (void) strlcat(cmd, temp, sizeof (cmd)); 1236 } 1237 (void) snprintf(temp, sizeof (temp), 1238 "%s.%d", ARCHIVE, part); 1239 if (isdir(temp) == 0) { 1240 (void) strlcat(cmd, " ", sizeof (cmd)); 1241 (void) strlcat(cmd, temp, sizeof (cmd)); 1242 } 1243 } else if (nparts) { 1244 for (i = 0; reloc_names[i] != NULL; i++) { 1245 if (iscpio(reloc_names[i], &iscomp) || 1246 isdir(reloc_names[i]) == 0) { 1247 (void) strlcat(cmd, " ", sizeof (cmd)); 1248 (void) strlcat(cmd, reloc_names[i], 1249 sizeof (cmd)); 1250 } 1251 } 1252 for (i = 0; root_names[i] != NULL; i++) { 1253 if (iscpio(root_names[i], &iscomp) || 1254 isdir(root_names[i]) == 0) { 1255 (void) strlcat(cmd, " ", sizeof (cmd)); 1256 (void) strlcat(cmd, root_names[i], 1257 sizeof (cmd)); 1258 } 1259 } 1260 if (isdir(ARCHIVE) == 0) { 1261 (void) strlcat(cmd, " ", sizeof (cmd)); 1262 (void) strlcat(cmd, ARCHIVE, sizeof (cmd)); 1263 } 1264 } 1265 if (options & PT_ODTSTREAM) { 1266 (void) snprintf(cmd + strlen(cmd), 1267 sizeof (cmd) - strlen(cmd), 1268 " -print | %s -ocD -C %d", 1269 CPIOPROC, (int)BLK_SIZE); 1270 } else { 1271 if (statvfs64(dstdir, &svfsb) == -1) { 1272 progerr(pkg_gt(ERR_TRANSFER)); 1273 logerr(pkg_gt(MSG_STATVFS), dstdir, errno); 1274 return (1); 1275 } 1276 1277 free_blocks = (((long)svfsb.f_frsize > 0) ? 1278 howmany(svfsb.f_frsize, DEV_BSIZE) : 1279 howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bavail; 1280 1281 if ((has_comp_size ? compressedsize : maxpartsize) > 1282 free_blocks) { 1283 progerr(pkg_gt(ERR_TRANSFER)); 1284 logerr(pkg_gt(MSG_NOSPACE), 1285 has_comp_size ? 1286 (long)compressedsize : (long)maxpartsize, 1287 free_blocks); 1288 return (1); 1289 } 1290 (void) snprintf(cmd + strlen(cmd), 1291 sizeof (cmd) - strlen(cmd), 1292 " -print | %s -pdum %s", 1293 CPIOPROC, dstdir); 1294 } 1295 1296 n = esystem(cmd, -1, (options & PT_ODTSTREAM) ? ds_fd : -1); 1297 if (n) { 1298 rpterr(); 1299 progerr(pkg_gt(ERR_TRANSFER)); 1300 logerr(pkg_gt(MSG_CMDFAIL), cmd, n); 1301 return (1); 1302 } 1303 1304 part++; 1305 if (srcdev.mount && (nparts > 1)) { 1306 /* unmount current source volume */ 1307 (void) chdir("/"); 1308 if (pkgumount(&srcdev)) 1309 return (1); 1310 /* loop until volume is mounted successfully */ 1311 while (part <= nparts) { 1312 /* read only */ 1313 n = pkgmount(&srcdev, NULL, part, nparts, 1); 1314 if (n) 1315 return (n); 1316 if (chdir(srcdir)) { 1317 progerr(pkg_gt(ERR_TRANSFER)); 1318 logerr(pkg_gt(MSG_CORRUPT)); 1319 (void) chdir("/"); 1320 (void) pkgumount(&srcdev); 1321 continue; 1322 } 1323 if (ckvolseq(srcdir, part, nparts)) { 1324 (void) chdir("/"); 1325 (void) pkgumount(&srcdev); 1326 continue; 1327 } 1328 break; 1329 } 1330 } 1331 if (!(options & PT_ODTSTREAM) && dstdev.mount) { 1332 /* unmount current volume */ 1333 if (pkgumount(&dstdev)) 1334 return (1); 1335 /* loop until next volume is mounted successfully */ 1336 while (part <= nparts) { 1337 /* writable */ 1338 n = pkgmount(&dstdev, NULL, part, nparts, 1); 1339 if (n) 1340 return (n); 1341 if (ckoverwrite(dst, dstinst, options)) 1342 continue; 1343 if (isdir(dstdir) && mkdir(dstdir, 0755)) { 1344 progerr(pkg_gt(ERR_TRANSFER)); 1345 logerr(pkg_gt(MSG_MKDIR), dstdir); 1346 continue; 1347 } 1348 break; 1349 } 1350 } 1351 1352 if ((options & PT_ODTSTREAM) && part <= nparts) { 1353 if (curpartcnt >= 0 && part > curpartcnt) { 1354 char prompt[128]; 1355 int index; 1356 ds_volno++; 1357 if (ds_close(0)) 1358 return (1); 1359 (void) sprintf(prompt, 1360 pkg_gt("Insert %%v %d of %d into %%p"), 1361 ds_volno, ds_volcnt); 1362 if (n = getvol(ods_name, NULL, DM_FORMAT, 1363 prompt)) 1364 return (n); 1365 if ((ds_fd = open(dstdev.cdevice, 1)) < 0) { 1366 progerr(pkg_gt(ERR_TRANSFER)); 1367 logerr(pkg_gt(MSG_OPEN), 1368 dstdev.cdevice, errno); 1369 return (1); 1370 } 1371 if (ds_ginit(dstdev.cdevice) < 0) { 1372 progerr(pkg_gt(ERR_TRANSFER)); 1373 logerr(pkg_gt(MSG_OPEN), 1374 dstdev.cdevice, errno); 1375 (void) ds_close(0); 1376 return (1); 1377 } 1378 1379 (void) sscanf(volnos, "%d %[ 0-9]", &index, 1380 tmpvol); 1381 (void) strlcpy(volnos, tmpvol, sizeof (volnos)); 1382 curpartcnt += index; 1383 } 1384 } 1385 1386 } 1387 return (0); 1388 } 1389 1390 static void 1391 sigtrap(int signo) 1392 { 1393 _NOTE(ARGUNUSED(signo)); 1394 signal_received++; 1395 } 1396 1397 static void 1398 cleanup(void) 1399 { 1400 (void) chdir("/"); 1401 if (tmpdir) { 1402 (void) rrmdir(tmpdir); 1403 free(tmpdir); 1404 tmpdir = NULL; 1405 } 1406 1407 if (tmppath) { 1408 /* remove any previous tmppath stuff */ 1409 (void) rrmdir(tmppath); 1410 free(tmppath); 1411 tmppath = NULL; 1412 } 1413 1414 if (tmpsymdir) { 1415 /* remove temp symbolic links made for signed pkg */ 1416 (void) rrmdir(tmpsymdir); 1417 free(tmpsymdir); 1418 tmpsymdir = NULL; 1419 } 1420 1421 if (srcdev.mount && !ids_name) 1422 (void) pkgumount(&srcdev); 1423 if (dstdev.mount && !ods_name) 1424 (void) pkgumount(&dstdev); 1425 (void) ds_close(1); 1426 } 1427