/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /*LINTLIBRARY*/ #ident "@(#)pkgtrans.c 1.14 94/10/21 SMI" /* SVr4.0 1.15.6.3 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pkglocale.h" extern char *pkgdir; /* pkgparam.c */ /* libadm.a */ extern char *devattr(char *device, char *attribute); extern char *fpkginst(char *pkg, ...); extern int fpkginfo(struct pkginfo *info, char *pkginst); extern int getvol(char *device, char *label, int options, char *prompt); extern int _getvol(char *device, char *label, int options, char *prompt, char *norewind); /* dstream.c */ extern int ds_ginit(char *device); extern int ds_close(int pkgendflg); #define CPIOPROC "/usr/bin/cpio" #define CMDSIZE 512 /* command block size */ #define HDR_PREFIX "# PaCkAgE DaTaStReAm\n" #define HDR_SUFFIX "# end of header\n" #define BLK_SIZE 512 /* size of logical block */ #define ENTRY_MAX 40 /* max size of entry for cpio cmd or header */ #define PKGINFO "pkginfo" #define PKGINFO_SIZE 7 /* strlen(PKGINFO) */ #define PKGMAP "pkgmap" #define PKGMAP_SIZE 6 /* strlen(PKGMAP) */ #define MAP_STAT_SIZE 60 /* 1st line of pkgmap (3 numbers & a : */ #define INSTALL "install" #define RELOC "reloc" #define ROOT "root" #define ARCHIVE "archive" #define MSG_TRANSFER "Transferring <%s> package instance\n" #define MSG_RENAME "\t... instance renamed <%s> on destination\n" #define MSG_CORRUPT \ "Volume is corrupt or is not part of the appropriate package." #define ERR_TRANSFER "unable to complete package transfer" #define MSG_SEQUENCE "- volume is out of sequence" #define MSG_MEM "- no memory" #define MSG_CMDFAIL "- process <%s> failed, exit code %d" #define MSG_POPEN "- popen of <%s> failed, errno=%d" #define MSG_PCLOSE "- pclose of <%s> failed, errno=%d" #define MSG_BADDEV "- invalid or unknown device <%s>" #define MSG_GETVOL "- unable to obtain package volume" #define MSG_NOSIZE "- unable to obtain maximum part size from pkgmap" #define MSG_CHDIR "- unable to change directory to <%s>" #define MSG_STATDIR "- unable to stat <%s>" #define MSG_CHOWNDIR "- unable to chown <%s>" #define MSG_CHMODDIR "- unable to chmod <%s>" #define MSG_FSTYP "- unable to determine filesystem type for <%s>" #define MSG_NOTEMP "- unable to create or use temporary directory <%s>" #define MSG_SAMEDEV "- source and destination represent the same device" #define MSG_NOTMPFIL "- unable to create or use temporary file <%s>" #define MSG_NOPKGMAP "- unable to open pkgmap for <%s>" #define MSG_BADPKGINFO "- unable to determine contents of pkginfo file" #define MSG_NOPKGS "- no packages were selected from <%s>" #define MSG_MKDIR "- unable to make directory <%s>" #define MSG_NOEXISTS "- package instance <%s> does not exist on source " \ "device" #define MSG_EXISTS "- no permission to overwrite existing path <%s>" #define MSG_DUPVERS "- identical version of <%s> already exists on " \ "destination device" #define MSG_TWODSTREAM "- both source and destination devices cannot be a " \ "datastream" #define MSG_NOSPACE "- not enough space on device" #define MSG_OPEN "- open of <%s> failed, errno=%d" #define MSG_STATVFS "- statvfs(%s) failed, errno=%d" static struct pkgdev srcdev, dstdev; static char *tmpdir; static char *tmppath; static char dstinst[16]; static char *ids_name, *ods_name; static int ds_volcnt; static int ds_volno; static int compressedsize, has_comp_size; static void (*func)(); static void cleanup(void); static void sigtrap(int signo); static int rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize); static int cat_and_count(); static int ckoverwrite(char *dir, char *inst, int options); static int pkgxfer(char *srcinst, int options); static int wdsheader(char *src, char *device, char **pkg); int pkgtrans(char *device1, char *device2, char **pkg, int options); extern int ds_fd; /* open file descriptor for data stream WHERE? */ static char *root_names[] = { "root", "root.cpio", "root.Z", "root.cpio.Z", 0 }; static char *reloc_names[] = { "reloc", "reloc.cpio", "reloc.Z", "reloc.cpio.Z", 0 }; char **xpkg; /* array of transferred packages */ int nxpkg; static char *allpkg[] = { "all", NULL }; static char *hdrbuf; static char *pinput, *nextpinput; int pkghead(char *device) { char *pt; int n; cleanup(); if (tmppath) { /* remove any previous tmppath stuff */ rrmdir(tmppath); free(tmppath); tmppath = NULL; } if (device == NULL) return (0); else if ((device[0] == '/') && !isdir(device)) { pkgdir = device; return (0); } else if ((pt = devattr(device, "pathname")) != NULL && !isdir(pt)) { pkgdir = pt; return (0); } /* check for datastream */ if (n = pkgtrans(device, (char *)0, allpkg, PT_SILENT|PT_INFO_ONLY)) return (n); /* pkgtrans has set pkgdir */ return (0); } static char * mgets(char *buf, int size) { nextpinput = strchr(pinput, '\n'); if (nextpinput == NULL) return (0); *nextpinput = '\0'; if ((int)strlen(pinput) > size) return (0); (void) strncpy(buf, pinput, strlen(pinput)); buf[strlen(pinput)] = '\0'; pinput = nextpinput + 1; return (buf); } /* * Here we construct the package size summaries for the headers. The * pkgmap file associated with fp must be rewound to the beginning of the * file. Note that we read three values from pkgmap first line in order * to get the *actual* size if this package is compressed. * This returns * 0 : error * 2 : not a compressed package * 3 : compressed package * and sets has_comp_size to indicate whether or not this is a compressed * package. */ static int rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize) { int n; char line_buffer[MAP_STAT_SIZE]; /* First read the null terminated first line */ if (fgets(line_buffer, MAP_STAT_SIZE, fp) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSIZE)); (void) fclose(fp); ecleanup(); return (0); } n = sscanf(line_buffer, ": %d %d %d", npts, maxpsz, cmpsize); if (n == 3) /* A valid compressed package entry */ has_comp_size = 1; else if (n == 2) /* A valid standard package entry */ has_comp_size = 0; else { /* invalid entry */ progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSIZE)); (void) fclose(fp); ecleanup(); return (0); } return (n); } /* will return 0, 1, 3, or 99 */ int pkgtrans(char *device1, char *device2, char **pkg, int options) { char *src, *dst; int errflg, i, n; func = signal(SIGINT, sigtrap); /* transfer spool to appropriate device */ if (devtype(device1, &srcdev)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADDEV), device1); return (1); } srcdev.rdonly++; /* check for datastream */ ids_name = NULL; if (srcdev.bdevice) { if (n = _getvol(srcdev.bdevice, NULL, NULL, pkg_gt("Insert %v into %p."), srcdev.norewind)) { cleanup(); if (n == 3) return (3); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_GETVOL)); return (1); } if (ds_readbuf(srcdev.cdevice)) ids_name = srcdev.cdevice; } if (srcdev.cdevice && !srcdev.bdevice) ids_name = srcdev.cdevice; else if (srcdev.pathname) { ids_name = srcdev.pathname; if (access(ids_name, 0) == -1) { progerr(ERR_TRANSFER); logerr(pkg_gt(MSG_GETVOL)); return (1); } } if (!ids_name && device2 == (char *)0) { if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) { cleanup(); return (n); } if (srcdev.mount && *srcdev.mount) pkgdir = strdup(srcdev.mount); return (0); } if (ids_name && device2 == (char *)0) { tmppath = tmpnam(NULL); tmppath = strdup(tmppath); if (tmppath == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); return (1); } if (mkdir(tmppath, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), tmppath); return (1); } device2 = tmppath; } if (devtype(device2, &dstdev)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADDEV), device2); return (1); } if ((srcdev.cdevice && dstdev.cdevice) && strcmp(srcdev.cdevice, dstdev.cdevice) == 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SAMEDEV)); return (1); } ods_name = NULL; if (dstdev.cdevice && !dstdev.bdevice || dstdev.pathname) options |= PT_ODTSTREAM; if (options & PT_ODTSTREAM) { if (!((ods_name = dstdev.cdevice) != NULL || (ods_name = dstdev.pathname) != NULL)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADDEV), device2); return (1); } if (ids_name) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_TWODSTREAM)); return (1); } } if ((srcdev.dirname && dstdev.dirname) && strcmp(srcdev.dirname, dstdev.dirname) == 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SAMEDEV)); return (1); } if ((srcdev.pathname && dstdev.pathname) && strcmp(srcdev.pathname, dstdev.pathname) == 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SAMEDEV)); return (1); } if (ids_name) { if (srcdev.cdevice && !srcdev.bdevice && (n = _getvol(srcdev.cdevice, NULL, NULL, NULL, srcdev.norewind))) { cleanup(); if (n == 3) return (3); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_GETVOL)); return (1); } if (srcdev.dirname = tmpnam(NULL)) tmpdir = srcdev.dirname = strdup(srcdev.dirname); if ((srcdev.dirname == NULL) || mkdir(srcdev.dirname, 0755) || chdir(srcdev.dirname)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTEMP), srcdev.dirname); cleanup(); return (1); } if (ds_init(ids_name, pkg, srcdev.norewind)) { cleanup(); return (1); } } else if (srcdev.mount) { if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) { cleanup(); return (n); } } src = srcdev.dirname; dst = dstdev.dirname; if (chdir(src)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), src); cleanup(); return (1); } xpkg = pkg = gpkglist(src, pkg); if (!pkg) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOPKGS), src); cleanup(); return (1); } for (nxpkg = 0; pkg[nxpkg]; /* void */) nxpkg++; /* count */ if (ids_name) ds_order(pkg); /* order requests */ if (options & PT_ODTSTREAM) { char line[128]; if (!dstdev.pathname && (n = _getvol(ods_name, NULL, DM_FORMAT, NULL, dstdev.norewind))) { cleanup(); if (n == 3) return (3); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_GETVOL)); return (1); } if (wdsheader(src, ods_name, pkg)) { cleanup(); return (1); } ds_volno = 1; /* number of volumes in datastream */ pinput = hdrbuf; /* skip past first line in header */ (void) mgets(line, 128); } errflg = 0; for (i = 0; pkg[i]; i++) { if (!(options & PT_ODTSTREAM) && dstdev.mount) { if (n = pkgmount(&dstdev, NULL, 0, 0, 1)) { cleanup(); return (n); } } if (errflg = pkgxfer(pkg[i], options)) { pkg[i] = NULL; if ((options & PT_ODTSTREAM) || (errflg != 2)) break; } else if (strcmp(dstinst, pkg[i])) pkg[i] = strdup(dstinst); } if (!(options & PT_ODTSTREAM) && dst) pkgdir = strdup(dst); cleanup(); return (errflg); } /* * This function concatenates append to the text described in the buf_ctrl * structure. This code modifies data in this structure and handles all * allocation issues. It returns '0' if everything was successful and '1' * if not. */ static int cat_and_count(struct dm_buf *buf_ctrl, char *append) { char *text_buffer_org; if (buf_ctrl->offset + (int)strlen(append) >= buf_ctrl->allocation) { text_buffer_org = buf_ctrl->text_buffer; /* save old */ /* reallocate (and maybe move) text buffer */ if ((buf_ctrl->text_buffer = (char *)realloc(buf_ctrl->text_buffer, buf_ctrl->allocation + BLK_SIZE)) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); free(buf_ctrl->text_buffer); return (1); } /* adjust insertion pointer in case the buffer was moved */ buf_ctrl->text_insert += (buf_ctrl->text_buffer - text_buffer_org); /* clear the new memory */ (void) memset(buf_ctrl->text_buffer + buf_ctrl->allocation, '\0', BLK_SIZE); buf_ctrl->allocation += BLK_SIZE; /* adjust total allocation */ hdrbuf = buf_ctrl->text_buffer; /* publish the text buffer */ } while (*append) { *(buf_ctrl->text_insert) = *append++; (buf_ctrl->text_insert)++; (buf_ctrl->offset)++; } return (0); } static int wdsheader(char *src, char *device, char **pkg) { FILE *fp; struct dm_buf buf_ctrl; char path[PATH_MAX], tmp_entry[ENTRY_MAX], tmp_file[L_tmpnam+1]; int i, n, nparts, maxpsize; int list_fd; int partcnt, totsize, block_cnt; struct stat statbuf; (void) ds_close(0); if (dstdev.pathname) ds_fd = creat(device, 0644); else ds_fd = open(device, 1); if (ds_fd < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), device, errno); return (1); } if (ds_ginit(device) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), device, errno); (void) ds_close(0); return (1); } if ((buf_ctrl.text_buffer = (char *)malloc(BLK_SIZE)) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); return (1); } hdrbuf = buf_ctrl.text_buffer; /* publish the text buffer */ /* clear the new memory */ (void) memset(buf_ctrl.text_buffer, '\0', BLK_SIZE); /* set up the buffer control structure for the header */ buf_ctrl.text_insert = buf_ctrl.text_buffer; buf_ctrl.offset = 0; buf_ctrl.allocation = BLK_SIZE; (void) cat_and_count(&buf_ctrl, HDR_PREFIX); nparts = maxpsize = 0; totsize = 0; for (i = 0; pkg[i]; i++) { (void) sprintf(path, "%s/%s/%s", src, pkg[i], PKGINFO); if (stat(path, &statbuf) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADPKGINFO)); ecleanup(); return (1); } totsize += statbuf.st_size/BLK_SIZE + 1; } /* * totsize contains number of blocks used by the pkginfo files */ totsize += i/4 + 1; if (dstdev.capacity && totsize > dstdev.capacity) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSPACE)); ecleanup(); return (1); } ds_volcnt = 1; for (i = 0; pkg[i]; i++) { partcnt = 0; (void) sprintf(path, "%s/%s/%s", src, pkg[i], PKGMAP); if ((fp = fopen(path, "r")) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOPKGMAP), pkg[i]); sighold(SIGINT); sigrelse(SIGINT); ecleanup(); return (1); } /* Evaluate the first entry in pkgmap */ n = rd_map_size(fp, &nparts, &maxpsize, &compressedsize); if (n == 3) /* It's a compressed package */ /* The header needs the *real* size */ maxpsize = compressedsize; else if (n == 0) /* pkgmap is corrupt */ return (1); if (dstdev.capacity && maxpsize > dstdev.capacity) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSPACE)); (void) fclose(fp); ecleanup(); return (1); } /* add pkg name, number of parts and the max part size */ (void) sprintf(tmp_entry, "%s %d %d", pkg[i], nparts, maxpsize); if (cat_and_count(&buf_ctrl, tmp_entry)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (1); } totsize += nparts * maxpsize; if (dstdev.capacity && dstdev.capacity < totsize) { int lastpartcnt = 0; #if 0 if (i != 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSPACE)); (void) fclose(fp); ecleanup(); return (1); } #endif /* 0 */ if (totsize) totsize -= nparts * maxpsize; while (partcnt < nparts) { while (totsize <= dstdev.capacity && partcnt <= nparts) { totsize += maxpsize; partcnt++; } /* partcnt == 0 means skip to next volume */ if (partcnt) partcnt--; (void) sprintf(tmp_entry, " %d", partcnt - lastpartcnt); if (cat_and_count(&buf_ctrl, tmp_entry)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (1); } ds_volcnt++; totsize = 0; lastpartcnt = partcnt; } /* first parts/volume number does not count */ ds_volcnt--; } if (cat_and_count(&buf_ctrl, "\n")) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (1); } (void) fclose(fp); } sighold(SIGINT); sigrelse(SIGINT); if (cat_and_count(&buf_ctrl, HDR_SUFFIX)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (1); } /* * The loop below assures compatibility with tapes that don't * have a block size (e.g.: Exabyte) by forcing EOR at the end * of each 512 bytes. */ for (block_cnt = 0; block_cnt < buf_ctrl.allocation; block_cnt += BLK_SIZE) write(ds_fd, (buf_ctrl.text_buffer + block_cnt), BLK_SIZE); /* * write the first cpio() archive to the datastream * which should contain the pkginfo & pkgmap files * for all packages */ (void) tmpnam(tmp_file); /* temporary file name */ if ((list_fd = open(tmp_file, O_RDWR | O_CREAT)) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL)); return (1); } /* * Create a cpio-compatible list of the requisite files in * the temporary file. */ for (i = 0; pkg[i]; i++) { register ssize_t entry_size; /* * Copy pkginfo and pkgmap filenames into the * temporary string allowing for the first line * as a special case. */ entry_size = sprintf(tmp_entry, (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", pkg[i], PKGINFO, pkg[i], PKGMAP); if (write(list_fd, tmp_entry, entry_size) != entry_size) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL)); (void) close(list_fd); ecleanup(); return (1); } } (void) lseek(list_fd, 0, SEEK_SET); #ifndef SUNOS41 (void) sprintf(tmp_entry, "%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); #else (void) sprintf(tmp_entry, "%s -oc -C %d", CPIOPROC, (int)BLK_SIZE); #endif if (n = esystem(tmp_entry, list_fd, ds_fd)) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CMDFAIL), tmp_entry, n); (void) close(list_fd); (void) unlink(tmp_file); cleanup(); return (1); } (void) close(list_fd); (void) unlink(tmp_file); return (0); } static int ckoverwrite(char *dir, char *inst, int options) { char path[PATH_MAX]; (void) sprintf(path, "%s/%s", dir, inst); if (access(path, 0) == 0) { if (options & PT_OVERWRITE) return (rrmdir(path)); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_EXISTS), path); return (1); } return (0); } static int pkgxfer(char *srcinst, int options) { struct pkginfo info; FILE *fp, *pp; char *pt, *src, *dst; char dstdir[PATH_MAX], temp[PATH_MAX], srcdir[PATH_MAX], cmd[CMDSIZE], pkgname[16]; int i, n, part, nparts, maxpartsize, curpartcnt, iscomp; char volnos[128], tmpvol[128]; struct statvfs svfsb; long free_blocks; struct stat srcstat; info.pkginst = NULL; /* required initialization */ /* * when this routine is entered, the first part of * the package to transfer is already available in * the directory indicated by 'src' --- unless the * source device is a datstream, in which case only * the pkginfo and pkgmap files are available in 'src' */ src = srcdev.dirname; dst = dstdev.dirname; if (!(options & PT_SILENT)) (void) fprintf(stderr, pkg_gt(MSG_TRANSFER), srcinst); (void) strcpy(dstinst, srcinst); if (!(options & PT_ODTSTREAM)) { /* destination is a (possibly mounted) directory */ (void) sprintf(dstdir, "%s/%s", dst, dstinst); /* * need to check destination directory to assure * that we will not be duplicating a package which * already resides there (though we are allowed to * overwrite the same version) */ pkgdir = src; if (fpkginfo(&info, srcinst)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOEXISTS), srcinst); (void) fpkginfo(&info, NULL); return (1); } pkgdir = dst; (void) strcpy(temp, srcinst); if (pt = strchr(temp, '.')) *pt = '\0'; (void) strcat(temp, ".*"); if (pt = fpkginst(temp, info.arch, info.version)) { /* * the same instance already exists, although * its pkgid might be different */ if (options & PT_OVERWRITE) { (void) strcpy(dstinst, pt); (void) sprintf(dstdir, "%s/%s", dst, dstinst); } else { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_DUPVERS), srcinst); (void) fpkginfo(&info, NULL); (void) fpkginst(NULL); return (2); } } else if (options & PT_RENAME) { /* * find next available instance by appending numbers * to the package abbreviation until the instance * does not exist in the destination directory */ if (pt = strchr(temp, '.')) *pt = '\0'; for (i = 2; (access(dstdir, 0) == 0); i++) { (void) sprintf(dstinst, "%s.%d", temp, i); (void) sprintf(dstdir, "%s/%s", dst, dstinst); } } else if (options & PT_OVERWRITE) { /* * we're allowed to overwrite, but there seems * to be no valid package to overwrite, and we are * not allowed to rename the destination, so act * as if we weren't given permission to overwrite * --- this keeps us from removing a destination * instance which is named the same as the source * instance, but really reflects a different pkg! */ options &= (~PT_OVERWRITE); } (void) fpkginfo(&info, NULL); (void) fpkginst(NULL); if (ckoverwrite(dst, dstinst, options)) return (2); if (isdir(dstdir) && mkdir(dstdir, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), dstdir); return (1); } (void) sprintf(srcdir, "%s/%s", src, srcinst); if (stat(srcdir, &srcstat) != -1) { if (chown(dstdir, srcstat.st_uid, srcstat.st_gid) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHOWNDIR), dstdir); return (1); } if (chmod(dstdir, (srcstat.st_mode & S_IAMB)) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHMODDIR), dstdir); return (1); } } else { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_STATDIR), srcdir); return (1); } } if (!(options & PT_SILENT) && strcmp(dstinst, srcinst)) (void) fprintf(stderr, pkg_gt(MSG_RENAME), dstinst); (void) sprintf(srcdir, "%s/%s", src, srcinst); if (chdir(srcdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), srcdir); return (1); } if (ids_name) { /* unpack the datatstream into a directory */ /* * transfer pkginfo & pkgmap first */ (void) sprintf(cmd, "%s -pudm %s", CPIOPROC, dstdir); if ((pp = epopen(cmd, "w")) == NULL) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_POPEN), cmd, errno); return (1); } (void) fprintf(pp, "%s\n%s\n", PKGINFO, PKGMAP); sighold(SIGINT); if (epclose(pp)) { sigrelse(SIGINT); rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_PCLOSE), cmd, errno); return (1); } sigrelse(SIGINT); if (options & PT_INFO_ONLY) return (0); /* don't transfer objects */ if (chdir(dstdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), dstdir); return (1); } /* * for each part of the package, use cpio() to * unpack the archive into the destination directory */ nparts = ds_findpkg(srcdev.cdevice, srcinst); if (nparts < 0) { progerr(pkg_gt(ERR_TRANSFER)); return (1); } for (part = 1; part <= nparts; /* void */) { if (ds_getpkg(srcdev.cdevice, part, dstdir)) { progerr(pkg_gt(ERR_TRANSFER)); return (1); } part++; if (dstdev.mount) { (void) chdir("/"); if (pkgumount(&dstdev)) return (1); if (part <= nparts) { if (n = pkgmount(&dstdev, NULL, part+1, nparts, 1)) return (n); if (ckoverwrite(dst, dstinst, options)) return (1); if (isdir(dstdir) && mkdir(dstdir, 0755)) { progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), dstdir); return (1); } /* * since volume is removable, each part * must contain a duplicate of the * pkginfo file to properly identify the * volume */ if (chdir(srcdir)) { progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), srcdir); return (1); } if ((pp = epopen(cmd, "w")) == NULL) { rpterr(); progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_POPEN), cmd, errno); return (1); } (void) fprintf(pp, "pkginfo"); if (epclose(pp)) { rpterr(); progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_PCLOSE), cmd, errno); return (1); } if (chdir(dstdir)) { progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), dstdir); return (1); } } } } return (0); } if ((fp = fopen(PKGMAP, "r")) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOPKGMAP), srcinst); return (1); } nparts = 1; if (!rd_map_size(fp, &nparts, &maxpartsize, &compressedsize)) return (1); else (void) fclose(fp); if (srcdev.mount) { if (ckvolseq(srcdir, 1, nparts)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SEQUENCE)); return (1); } } /* write each part of this package */ if (options & PT_ODTSTREAM) { char line[128]; (void) mgets(line, 128); curpartcnt = -1; if (sscanf(line, "%s %d %d %[ 0-9]", &pkgname, &nparts, &maxpartsize, volnos) == 4) { sscanf(volnos, "%d %[ 0-9]", &curpartcnt, tmpvol); strcpy(volnos, tmpvol); } } for (part = 1; part <= nparts; /* void */) { if (curpartcnt == 0 && (options & PT_ODTSTREAM)) { char prompt[128]; int index; ds_volno++; (void) ds_close(0); (void) sprintf(prompt, pkg_gt("Insert %%v %d of %d into %%p"), ds_volno, ds_volcnt); if (n = getvol(ods_name, NULL, DM_FORMAT, prompt)) return (n); if ((ds_fd = open(dstdev.cdevice, 1)) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); return (1); } if (ds_ginit(dstdev.cdevice) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); (void) ds_close(0); return (1); } (void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol); (void) strcpy(volnos, tmpvol); curpartcnt += index; } if (options & PT_INFO_ONLY) nparts = 0; if (part == 1) { (void) sprintf(cmd, "find %s %s", PKGINFO, PKGMAP); if (nparts && (isdir(INSTALL) == 0)) { (void) strcat(cmd, " "); (void) strcat(cmd, INSTALL); } } else (void) sprintf(cmd, "find %s", PKGINFO); if (nparts > 1) { (void) sprintf(temp, "%s.%d", RELOC, part); if (iscpio(temp, &iscomp) || isdir(temp) == 0) { (void) strcat(cmd, " "); (void) strcat(cmd, temp); } (void) sprintf(temp, "%s.%d", ROOT, part); if (iscpio(temp, &iscomp) || isdir(temp) == 0) { (void) strcat(cmd, " "); (void) strcat(cmd, temp); } (void) sprintf(temp, "%s.%d", ARCHIVE, part); if (isdir(temp) == 0) { (void) strcat(cmd, " "); (void) strcat(cmd, temp); } } else if (nparts) { for (i = 0; reloc_names[i] != NULL; i++) { if (iscpio(reloc_names[i], &iscomp) || isdir(reloc_names[i]) == 0) { (void) strcat(cmd, " "); (void) strcat(cmd, reloc_names[i]); } } for (i = 0; root_names[i] != NULL; i++) { if (iscpio(root_names[i], &iscomp) || isdir(root_names[i]) == 0) { (void) strcat(cmd, " "); (void) strcat(cmd, root_names[i]); } } if (isdir(ARCHIVE) == 0) { (void) strcat(cmd, " "); (void) strcat(cmd, ARCHIVE); } } if (options & PT_ODTSTREAM) { #ifndef SUNOS41 (void) sprintf(cmd+strlen(cmd), " -print | %s -ocD -C %d", #else (void) sprintf(cmd+strlen(cmd), " -print | %s -oc -C %d", #endif CPIOPROC, (int)BLK_SIZE); } else { if (statvfs(dstdir, &svfsb) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_STATVFS), dstdir, errno); return (1); } free_blocks = (((long)svfsb.f_frsize > 0) ? howmany(svfsb.f_frsize, DEV_BSIZE) : howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bavail; if ((has_comp_size ? compressedsize : maxpartsize) > free_blocks) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSPACE)); return (1); } (void) sprintf(cmd+strlen(cmd), " -print | %s -pdum %s", CPIOPROC, dstdir); } n = esystem(cmd, -1, (options & PT_ODTSTREAM) ? ds_fd : -1); if (n) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CMDFAIL), cmd, n); return (1); } part++; if (srcdev.mount && (nparts > 1)) { /* unmount current source volume */ (void) chdir("/"); if (pkgumount(&srcdev)) return (1); /* loop until volume is mounted successfully */ while (part <= nparts) { /* read only */ n = pkgmount(&srcdev, NULL, part, nparts, 1); if (n) return (n); if (chdir(srcdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CORRUPT), srcdir); (void) chdir("/"); pkgumount(&srcdev); continue; } if (ckvolseq(srcdir, part, nparts)) { (void) chdir("/"); pkgumount(&srcdev); continue; } break; } } if (!(options & PT_ODTSTREAM) && dstdev.mount) { /* unmount current volume */ if (pkgumount(&dstdev)) return (1); /* loop until next volume is mounted successfully */ while (part <= nparts) { /* writable */ n = pkgmount(&dstdev, NULL, part, nparts, 1); if (n) return (n); if (ckoverwrite(dst, dstinst, options)) continue; if (isdir(dstdir) && mkdir(dstdir, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), dstdir); continue; } break; } } if ((options & PT_ODTSTREAM) && part <= nparts) { if (curpartcnt >= 0 && part > curpartcnt) { char prompt[128]; int index; ds_volno++; if (ds_close(0)) return (1); (void) sprintf(prompt, pkg_gt("Insert %%v %d of %d into %%p"), ds_volno, ds_volcnt); if (n = getvol(ods_name, NULL, DM_FORMAT, prompt)) return (n); if ((ds_fd = open(dstdev.cdevice, 1)) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); return (1); } if (ds_ginit(dstdev.cdevice) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); (void) ds_close(0); return (1); } (void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol); (void) strcpy(volnos, tmpvol); curpartcnt += index; } } } return (0); } static void sigtrap(int signo) { cleanup(); if (tmppath) { rrmdir(tmppath); free(tmppath); tmppath = NULL; } if (func && (func != SIG_DFL) && (func != SIG_IGN)) /* must have been an interrupt handler */ (*func)(signo); } static void cleanup(void) { chdir("/"); if (tmpdir) { rrmdir(tmpdir); free(tmpdir); tmpdir = NULL; } if (srcdev.mount && !ids_name) pkgumount(&srcdev); if (dstdev.mount && !ods_name) pkgumount(&dstdev); (void) ds_close(1); }