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, NULL, 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, NULL, 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], 901 temp[PATH_MAX], 902 srcdir[PATH_MAX], 903 cmd[CMDSIZE], 904 pkgname[NON_ABI_NAMELNGTH]; 905 int i, n, part, nparts, maxpartsize, curpartcnt, iscomp; 906 char volnos[128], tmpvol[128]; 907 struct statvfs64 svfsb; 908 longlong_t free_blocks; 909 struct stat srcstat; 910 911 info.pkginst = NULL; /* required initialization */ 912 913 /* 914 * when this routine is entered, the first part of 915 * the package to transfer is already available in 916 * the directory indicated by 'src' --- unless the 917 * source device is a datstream, in which case only 918 * the pkginfo and pkgmap files are available in 'src' 919 */ 920 src = srcdev.dirname; 921 dst = dstdev.dirname; 922 923 if (!(options & PT_SILENT)) 924 (void) fprintf(stderr, pkg_gt(MSG_TRANSFER), srcinst); 925 (void) strlcpy(dstinst, srcinst, sizeof (dstinst)); 926 927 if (!(options & PT_ODTSTREAM)) { 928 /* destination is a (possibly mounted) directory */ 929 (void) snprintf(dstdir, sizeof (dstdir), 930 "%s/%s", dst, dstinst); 931 932 /* 933 * need to check destination directory to assure 934 * that we will not be duplicating a package which 935 * already resides there (though we are allowed to 936 * overwrite the same version) 937 */ 938 pkgdir = src; 939 if (fpkginfo(&info, srcinst)) { 940 progerr(pkg_gt(ERR_TRANSFER)); 941 logerr(pkg_gt(MSG_NOEXISTS), srcinst); 942 (void) fpkginfo(&info, NULL); 943 return (1); 944 } 945 pkgdir = dst; 946 947 (void) strlcpy(temp, srcinst, sizeof (temp)); 948 if (pt = strchr(temp, '.')) 949 *pt = '\0'; 950 (void) strlcat(temp, ".*", sizeof (temp)); 951 952 if (pt = fpkginst(temp, info.arch, info.version)) { 953 /* 954 * the same instance already exists, although 955 * its pkgid might be different 956 */ 957 if (options & PT_OVERWRITE) { 958 (void) strlcpy(dstinst, pt, sizeof (dstinst)); 959 (void) snprintf(dstdir, sizeof (dstdir), 960 "%s/%s", dst, dstinst); 961 } else { 962 progerr(pkg_gt(ERR_TRANSFER)); 963 logerr(pkg_gt(MSG_DUPVERS), srcinst); 964 (void) fpkginfo(&info, NULL); 965 (void) fpkginst(NULL); 966 return (2); 967 } 968 } else if (options & PT_RENAME) { 969 /* 970 * find next available instance by appending numbers 971 * to the package abbreviation until the instance 972 * does not exist in the destination directory 973 */ 974 if (pt = strchr(temp, '.')) 975 *pt = '\0'; 976 for (i = 2; (access(dstdir, 0) == 0); i++) { 977 (void) snprintf(dstinst, sizeof (dstinst), 978 "%s.%d", temp, i); 979 (void) snprintf(dstdir, sizeof (dstdir), 980 "%s/%s", dst, dstinst); 981 } 982 } else if (options & PT_OVERWRITE) { 983 /* 984 * we're allowed to overwrite, but there seems 985 * to be no valid package to overwrite, and we are 986 * not allowed to rename the destination, so act 987 * as if we weren't given permission to overwrite 988 * --- this keeps us from removing a destination 989 * instance which is named the same as the source 990 * instance, but really reflects a different pkg! 991 */ 992 options &= (~PT_OVERWRITE); 993 } 994 (void) fpkginfo(&info, NULL); 995 (void) fpkginst(NULL); 996 997 if (ckoverwrite(dst, dstinst, options)) 998 return (2); 999 1000 if (isdir(dstdir) && mkdir(dstdir, 0755)) { 1001 progerr(pkg_gt(ERR_TRANSFER)); 1002 logerr(pkg_gt(MSG_MKDIR), dstdir); 1003 return (1); 1004 } 1005 1006 (void) snprintf(srcdir, sizeof (srcdir), 1007 "%s/%s", src, srcinst); 1008 if (stat(srcdir, &srcstat) != -1) { 1009 if (chmod(dstdir, (srcstat.st_mode & S_IAMB)) == -1) { 1010 progerr(pkg_gt(ERR_TRANSFER)); 1011 logerr(pkg_gt(MSG_CHMODDIR), dstdir); 1012 return (1); 1013 } 1014 } else { 1015 progerr(pkg_gt(ERR_TRANSFER)); 1016 logerr(pkg_gt(MSG_STATDIR), srcdir); 1017 return (1); 1018 } 1019 } 1020 1021 if (!(options & PT_SILENT) && strcmp(dstinst, srcinst)) 1022 (void) fprintf(stderr, pkg_gt(MSG_RENAME), dstinst); 1023 1024 (void) snprintf(srcdir, sizeof (srcdir), "%s/%s", src, srcinst); 1025 if (chdir(srcdir)) { 1026 progerr(pkg_gt(ERR_TRANSFER)); 1027 logerr(pkg_gt(MSG_CHDIR), srcdir); 1028 return (1); 1029 } 1030 1031 if (ids_name) { /* unpack the datatstream into a directory */ 1032 /* 1033 * transfer pkginfo & pkgmap first 1034 */ 1035 (void) snprintf(cmd, sizeof (cmd), 1036 "%s -pudm %s", CPIOPROC, dstdir); 1037 if ((pp = epopen(cmd, "w")) == NULL) { 1038 rpterr(); 1039 progerr(pkg_gt(ERR_TRANSFER)); 1040 logerr(pkg_gt(MSG_POPEN), cmd, errno); 1041 return (1); 1042 } 1043 (void) fprintf(pp, "%s\n%s\n", PKGINFO, PKGMAP); 1044 1045 (void) sighold(SIGINT); 1046 (void) sighold(SIGHUP); 1047 r = epclose(pp); 1048 (void) sigrelse(SIGINT); 1049 (void) sigrelse(SIGHUP); 1050 1051 if (r != 0) { 1052 rpterr(); 1053 progerr(pkg_gt(ERR_TRANSFER)); 1054 logerr(pkg_gt(MSG_PCLOSE), cmd, errno); 1055 return (1); 1056 } 1057 1058 if (options & PT_INFO_ONLY) 1059 return (0); /* don't transfer objects */ 1060 1061 if (chdir(dstdir)) { 1062 progerr(pkg_gt(ERR_TRANSFER)); 1063 logerr(pkg_gt(MSG_CHDIR), dstdir); 1064 return (1); 1065 } 1066 1067 /* 1068 * for each part of the package, use cpio() to 1069 * unpack the archive into the destination directory 1070 */ 1071 nparts = ds_findpkg(srcdev.cdevice, srcinst); 1072 if (nparts < 0) { 1073 progerr(pkg_gt(ERR_TRANSFER)); 1074 return (1); 1075 } 1076 for (part = 1; part <= nparts; /* void */) { 1077 if (ds_getpkg(srcdev.cdevice, part, dstdir)) { 1078 progerr(pkg_gt(ERR_TRANSFER)); 1079 return (1); 1080 } 1081 part++; 1082 if (dstdev.mount) { 1083 (void) chdir("/"); 1084 if (pkgumount(&dstdev)) 1085 return (1); 1086 if (part <= nparts) { 1087 if (n = pkgmount(&dstdev, NULL, part+1, 1088 nparts, 1)) 1089 return (n); 1090 if (ckoverwrite(dst, dstinst, options)) 1091 return (1); 1092 if (isdir(dstdir) && 1093 mkdir(dstdir, 0755)) { 1094 progerr( 1095 pkg_gt(ERR_TRANSFER)); 1096 logerr(pkg_gt(MSG_MKDIR), 1097 dstdir); 1098 return (1); 1099 } 1100 /* 1101 * since volume is removable, each part 1102 * must contain a duplicate of the 1103 * pkginfo file to properly identify the 1104 * volume 1105 */ 1106 if (chdir(srcdir)) { 1107 progerr( 1108 pkg_gt(ERR_TRANSFER)); 1109 logerr(pkg_gt(MSG_CHDIR), 1110 srcdir); 1111 return (1); 1112 } 1113 if ((pp = epopen(cmd, "w")) == NULL) { 1114 rpterr(); 1115 progerr( 1116 pkg_gt(ERR_TRANSFER)); 1117 logerr(pkg_gt(MSG_POPEN), 1118 cmd, errno); 1119 return (1); 1120 } 1121 (void) fprintf(pp, "pkginfo"); 1122 1123 (void) sighold(SIGINT); 1124 (void) sighold(SIGHUP); 1125 r = epclose(pp); 1126 (void) sigrelse(SIGINT); 1127 (void) sigrelse(SIGHUP); 1128 1129 if (r != 0) { 1130 rpterr(); 1131 progerr( 1132 pkg_gt(ERR_TRANSFER)); 1133 logerr(pkg_gt(MSG_PCLOSE), 1134 cmd, errno); 1135 return (1); 1136 } 1137 if (chdir(dstdir)) { 1138 progerr( 1139 pkg_gt(ERR_TRANSFER)); 1140 logerr(pkg_gt(MSG_CHDIR), 1141 dstdir); 1142 return (1); 1143 } 1144 } 1145 } 1146 } 1147 return (0); 1148 } 1149 1150 if ((fp = fopen(PKGMAP, "r")) == NULL) { 1151 progerr(pkg_gt(ERR_TRANSFER)); 1152 logerr(pkg_gt(MSG_NOPKGMAP), srcinst); 1153 return (1); 1154 } 1155 1156 nparts = 1; 1157 if (!rd_map_size(fp, &nparts, &maxpartsize, &compressedsize)) 1158 return (1); 1159 else 1160 (void) fclose(fp); 1161 1162 if (srcdev.mount) { 1163 if (ckvolseq(srcdir, 1, nparts)) { 1164 progerr(pkg_gt(ERR_TRANSFER)); 1165 logerr(pkg_gt(MSG_SEQUENCE)); 1166 return (1); 1167 } 1168 } 1169 1170 /* write each part of this package */ 1171 if (options & PT_ODTSTREAM) { 1172 char line[128]; 1173 (void) mgets(line, 128); 1174 curpartcnt = -1; 1175 /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 1176 if (sscanf(line, "%s %d %d %[ 0-9]", pkgname, &nparts, 1177 &maxpartsize, volnos) == 4) { 1178 (void) sscanf(volnos, 1179 "%d %[ 0-9]", &curpartcnt, tmpvol); 1180 (void) strlcpy(volnos, tmpvol, sizeof (volnos)); 1181 } 1182 } 1183 1184 for (part = 1; part <= nparts; /* void */) { 1185 if (curpartcnt == 0 && (options & PT_ODTSTREAM)) { 1186 char prompt[128]; 1187 int index; 1188 ds_volno++; 1189 (void) ds_close(0); 1190 (void) sprintf(prompt, 1191 pkg_gt("Insert %%v %d of %d into %%p"), 1192 ds_volno, ds_volcnt); 1193 if (n = getvol(ods_name, NULL, DM_FORMAT, prompt)) 1194 return (n); 1195 if ((ds_fd = open(dstdev.cdevice, O_WRONLY)) < 0) { 1196 progerr(pkg_gt(ERR_TRANSFER)); 1197 logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, 1198 errno); 1199 return (1); 1200 } 1201 if (ds_ginit(dstdev.cdevice) < 0) { 1202 progerr(pkg_gt(ERR_TRANSFER)); 1203 logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, 1204 errno); 1205 (void) ds_close(0); 1206 return (1); 1207 } 1208 1209 (void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol); 1210 (void) strlcpy(volnos, tmpvol, sizeof (volnos)); 1211 curpartcnt += index; 1212 } 1213 1214 if (options & PT_INFO_ONLY) 1215 nparts = 0; 1216 1217 if (part == 1) { 1218 (void) snprintf(cmd, sizeof (cmd), 1219 "find %s %s", PKGINFO, PKGMAP); 1220 if (nparts && (isdir(INSTALL) == 0)) { 1221 (void) strlcat(cmd, " ", sizeof (cmd)); 1222 (void) strlcat(cmd, INSTALL, sizeof (cmd)); 1223 } 1224 } else 1225 (void) snprintf(cmd, sizeof (cmd), "find %s", PKGINFO); 1226 1227 if (nparts > 1) { 1228 (void) snprintf(temp, sizeof (temp), 1229 "%s.%d", RELOC, part); 1230 if (iscpio(temp, &iscomp) || isdir(temp) == 0) { 1231 (void) strlcat(cmd, " ", sizeof (cmd)); 1232 (void) strlcat(cmd, temp, sizeof (cmd)); 1233 } 1234 (void) snprintf(temp, sizeof (temp), 1235 "%s.%d", ROOT, part); 1236 if (iscpio(temp, &iscomp) || isdir(temp) == 0) { 1237 (void) strlcat(cmd, " ", sizeof (cmd)); 1238 (void) strlcat(cmd, temp, sizeof (cmd)); 1239 } 1240 (void) snprintf(temp, sizeof (temp), 1241 "%s.%d", ARCHIVE, part); 1242 if (isdir(temp) == 0) { 1243 (void) strlcat(cmd, " ", sizeof (cmd)); 1244 (void) strlcat(cmd, temp, sizeof (cmd)); 1245 } 1246 } else if (nparts) { 1247 for (i = 0; reloc_names[i] != NULL; i++) { 1248 if (iscpio(reloc_names[i], &iscomp) || 1249 isdir(reloc_names[i]) == 0) { 1250 (void) strlcat(cmd, " ", sizeof (cmd)); 1251 (void) strlcat(cmd, reloc_names[i], 1252 sizeof (cmd)); 1253 } 1254 } 1255 for (i = 0; root_names[i] != NULL; i++) { 1256 if (iscpio(root_names[i], &iscomp) || 1257 isdir(root_names[i]) == 0) { 1258 (void) strlcat(cmd, " ", sizeof (cmd)); 1259 (void) strlcat(cmd, root_names[i], 1260 sizeof (cmd)); 1261 } 1262 } 1263 if (isdir(ARCHIVE) == 0) { 1264 (void) strlcat(cmd, " ", sizeof (cmd)); 1265 (void) strlcat(cmd, ARCHIVE, sizeof (cmd)); 1266 } 1267 } 1268 if (options & PT_ODTSTREAM) { 1269 (void) snprintf(cmd + strlen(cmd), 1270 sizeof (cmd) - strlen(cmd), 1271 " -print | %s -ocD -C %d", 1272 CPIOPROC, (int)BLK_SIZE); 1273 } else { 1274 if (statvfs64(dstdir, &svfsb) == -1) { 1275 progerr(pkg_gt(ERR_TRANSFER)); 1276 logerr(pkg_gt(MSG_STATVFS), dstdir, errno); 1277 return (1); 1278 } 1279 1280 free_blocks = (((long)svfsb.f_frsize > 0) ? 1281 howmany(svfsb.f_frsize, DEV_BSIZE) : 1282 howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bavail; 1283 1284 if ((has_comp_size ? compressedsize : maxpartsize) > 1285 free_blocks) { 1286 progerr(pkg_gt(ERR_TRANSFER)); 1287 logerr(pkg_gt(MSG_NOSPACE), 1288 has_comp_size ? 1289 (long)compressedsize : (long)maxpartsize, 1290 free_blocks); 1291 return (1); 1292 } 1293 (void) snprintf(cmd + strlen(cmd), 1294 sizeof (cmd) - strlen(cmd), 1295 " -print | %s -pdum %s", 1296 CPIOPROC, dstdir); 1297 } 1298 1299 n = esystem(cmd, -1, (options & PT_ODTSTREAM) ? ds_fd : -1); 1300 if (n) { 1301 rpterr(); 1302 progerr(pkg_gt(ERR_TRANSFER)); 1303 logerr(pkg_gt(MSG_CMDFAIL), cmd, n); 1304 return (1); 1305 } 1306 1307 part++; 1308 if (srcdev.mount && (nparts > 1)) { 1309 /* unmount current source volume */ 1310 (void) chdir("/"); 1311 if (pkgumount(&srcdev)) 1312 return (1); 1313 /* loop until volume is mounted successfully */ 1314 while (part <= nparts) { 1315 /* read only */ 1316 n = pkgmount(&srcdev, NULL, part, nparts, 1); 1317 if (n) 1318 return (n); 1319 if (chdir(srcdir)) { 1320 progerr(pkg_gt(ERR_TRANSFER)); 1321 logerr(pkg_gt(MSG_CORRUPT)); 1322 (void) chdir("/"); 1323 (void) pkgumount(&srcdev); 1324 continue; 1325 } 1326 if (ckvolseq(srcdir, part, nparts)) { 1327 (void) chdir("/"); 1328 (void) pkgumount(&srcdev); 1329 continue; 1330 } 1331 break; 1332 } 1333 } 1334 if (!(options & PT_ODTSTREAM) && dstdev.mount) { 1335 /* unmount current volume */ 1336 if (pkgumount(&dstdev)) 1337 return (1); 1338 /* loop until next volume is mounted successfully */ 1339 while (part <= nparts) { 1340 /* writable */ 1341 n = pkgmount(&dstdev, NULL, part, nparts, 1); 1342 if (n) 1343 return (n); 1344 if (ckoverwrite(dst, dstinst, options)) 1345 continue; 1346 if (isdir(dstdir) && mkdir(dstdir, 0755)) { 1347 progerr(pkg_gt(ERR_TRANSFER)); 1348 logerr(pkg_gt(MSG_MKDIR), dstdir); 1349 continue; 1350 } 1351 break; 1352 } 1353 } 1354 1355 if ((options & PT_ODTSTREAM) && part <= nparts) { 1356 if (curpartcnt >= 0 && part > curpartcnt) { 1357 char prompt[128]; 1358 int index; 1359 ds_volno++; 1360 if (ds_close(0)) 1361 return (1); 1362 (void) sprintf(prompt, 1363 pkg_gt("Insert %%v %d of %d into %%p"), 1364 ds_volno, ds_volcnt); 1365 if (n = getvol(ods_name, NULL, DM_FORMAT, 1366 prompt)) 1367 return (n); 1368 if ((ds_fd = open(dstdev.cdevice, 1)) < 0) { 1369 progerr(pkg_gt(ERR_TRANSFER)); 1370 logerr(pkg_gt(MSG_OPEN), 1371 dstdev.cdevice, errno); 1372 return (1); 1373 } 1374 if (ds_ginit(dstdev.cdevice) < 0) { 1375 progerr(pkg_gt(ERR_TRANSFER)); 1376 logerr(pkg_gt(MSG_OPEN), 1377 dstdev.cdevice, errno); 1378 (void) ds_close(0); 1379 return (1); 1380 } 1381 1382 (void) sscanf(volnos, "%d %[ 0-9]", &index, 1383 tmpvol); 1384 (void) strlcpy(volnos, tmpvol, sizeof (volnos)); 1385 curpartcnt += index; 1386 } 1387 } 1388 1389 } 1390 return (0); 1391 } 1392 1393 static void 1394 sigtrap(int signo) 1395 { 1396 _NOTE(ARGUNUSED(signo)); 1397 signal_received++; 1398 } 1399 1400 static void 1401 cleanup(void) 1402 { 1403 (void) chdir("/"); 1404 if (tmpdir) { 1405 (void) rrmdir(tmpdir); 1406 free(tmpdir); 1407 tmpdir = NULL; 1408 } 1409 1410 if (tmppath) { 1411 /* remove any previous tmppath stuff */ 1412 (void) rrmdir(tmppath); 1413 free(tmppath); 1414 tmppath = NULL; 1415 } 1416 1417 if (tmpsymdir) { 1418 /* remove temp symbolic links made for signed pkg */ 1419 (void) rrmdir(tmpsymdir); 1420 free(tmpsymdir); 1421 tmpsymdir = NULL; 1422 } 1423 1424 if (srcdev.mount && !ids_name) 1425 (void) pkgumount(&srcdev); 1426 if (dstdev.mount && !ods_name) 1427 (void) pkgumount(&dstdev); 1428 (void) ds_close(1); 1429 } 1430