/* * 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); }
int epclose(FILE *pp) { int n; n = pclose(pp); if (n == 0) ecleanup(); return (n); }
static int wdsheader(struct dm_buf *hdr, char *src, char *device, char **pkg, PKCS7 *sig) { FILE *fp; char path[PATH_MAX], tmp_entry[ENTRY_MAX], tmp_file[L_tmpnam+1]; char srcpath[PATH_MAX]; int i, n; int list_fd; int block_cnt; int len; char cwd[MAXPATHLEN + 1]; boolean_t making_sig = B_FALSE; making_sig = (sig != NULL) ? B_TRUE : B_FALSE; (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); } /* * 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 < hdr->allocation; block_cnt += BLK_SIZE) { (void) write(ds_fd, (hdr->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, 0644)) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); return (1); } /* * Create a cpio-compatible list of the requisite files in * the temporary file. */ if (!making_sig) { 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), tmp_file); (void) close(list_fd); ecleanup(); return (1); } } } else { register ssize_t entry_size; /* * if we're making a signature, we must make a * temporary area full of symlinks to the requisite * files, plus an extra entry for the signature, so * that cpio will put all files and signature in the * same archive in a single invocation of cpio. */ tmpsymdir = xstrdup(tmpnam(NULL)); if (mkdir(tmpsymdir, S_IRWXU)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), tmpsymdir); return (1); } /* generate the signature */ if (((len = snprintf(path, PATH_MAX, "%s/%s", tmpsymdir, SIGNATURE_FILENAME)) >= PATH_MAX) || len < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmpsymdir); cleanup(); return (1); } if ((fp = fopen(path, "w")) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), path); cleanup(); return (1); } (void) PEM_write_PKCS7(fp, sig); (void) fclose(fp); for (i = 0; pkg[i]; i++) { (void) snprintf(path, sizeof (path), "%s/%s", tmpsymdir, pkg[i]); if (mkdir(path, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), path); cleanup(); return (1); } (void) snprintf(path, sizeof (path), "%s/%s/%s", tmpsymdir, pkg[i], PKGINFO); (void) snprintf(srcpath, sizeof (srcpath), "%s/%s/%s", src, pkg[i], PKGINFO); if (symlink(srcpath, path) != 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SYMLINK), path, srcpath); cleanup(); return (1); } (void) snprintf(path, sizeof (path), "%s/%s/%s", tmpsymdir, pkg[i], PKGMAP); (void) snprintf(srcpath, sizeof (srcpath), "%s/%s/%s", src, pkg[i], PKGMAP); if (symlink(srcpath, path) != 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SYMLINK), path, srcpath); cleanup(); return (1); } /* * Copy pkginfo and pkgmap filenames into the * temporary string allowing for the first line * as a special case. */ entry_size = snprintf(tmp_entry, sizeof (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), tmp_file); (void) close(list_fd); ecleanup(); cleanup(); return (1); } } /* add signature to list of files */ entry_size = snprintf(tmp_entry, sizeof (tmp_entry), "\n%s", SIGNATURE_FILENAME); if (write(list_fd, tmp_entry, entry_size) != entry_size) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); (void) close(list_fd); ecleanup(); cleanup(); return (1); } } (void) lseek(list_fd, 0, SEEK_SET); if (!making_sig) { (void) snprintf(tmp_entry, sizeof (tmp_entry), "%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); } else { /* * when making a signature, we must make sure to follow * symlinks during the cpio so that we don't archive * the links themselves */ (void) snprintf(tmp_entry, sizeof (tmp_entry), "%s -ocDL -C %d", CPIOPROC, (int)BLK_SIZE); } if (making_sig) { /* save cwd and change to symlink dir for cpio invocation */ if (getcwd(cwd, MAXPATHLEN + 1) == NULL) { logerr(pkg_gt(ERR_GETWD)); progerr(pkg_gt(ERR_TRANSFER)); cleanup(); return (1); } if (chdir(tmpsymdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), tmpsymdir); cleanup(); return (1); } } 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); if (making_sig) { /* change to back to src dir for subsequent operations */ if (chdir(cwd)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), cwd); cleanup(); return (1); } } return (0); }
static struct dm_buf * genheader(char *src, char **pkg) { FILE *fp; char path[MAXPATHLEN], tmp_entry[ENTRY_MAX]; int i, n, nparts, maxpsize; int partcnt; long totsize; struct stat statbuf; if ((hdrbuf.text_buffer = (char *)malloc(BLK_SIZE)) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); return (NULL); } /* clear the new memory */ (void) memset(hdrbuf.text_buffer, '\0', BLK_SIZE); /* set up the buffer control structure for the header */ hdrbuf.offset = 0; hdrbuf.allocation = BLK_SIZE; (void) cat_and_count(&hdrbuf, HDR_PREFIX); (void) cat_and_count(&hdrbuf, "\n"); nparts = maxpsize = 0; totsize = 0; for (i = 0; pkg[i]; i++) { (void) snprintf(path, MAXPATHLEN, "%s/%s/%s", src, pkg[i], PKGINFO); if (stat(path, &statbuf) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADPKGINFO)); ecleanup(); return (NULL); } 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), totsize, dstdev.capacity); ecleanup(); return (NULL); } ds_volcnt = 1; for (i = 0; pkg[i]; i++) { partcnt = 0; (void) snprintf(path, MAXPATHLEN, "%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]); ecleanup(); return (NULL); } /* 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 (NULL); if (dstdev.capacity && maxpsize > dstdev.capacity) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSPACE), (long)maxpsize, dstdev.capacity); (void) fclose(fp); ecleanup(); return (NULL); } /* add pkg name, number of parts and the max part size */ if (snprintf(tmp_entry, ENTRY_MAX, "%s %d %d", pkg[i], nparts, maxpsize) >= ENTRY_MAX) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(ERR_MEM)); (void) fclose(fp); ecleanup(); return (NULL); } if (cat_and_count(&hdrbuf, tmp_entry)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (NULL); } totsize += nparts * maxpsize; if (dstdev.capacity && dstdev.capacity < totsize) { int lastpartcnt = 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) snprintf(tmp_entry, ENTRY_MAX, " %d", partcnt - lastpartcnt); if (cat_and_count(&hdrbuf, tmp_entry)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (NULL); } ds_volcnt++; totsize = 0; lastpartcnt = partcnt; } /* first parts/volume number does not count */ ds_volcnt--; } if (cat_and_count(&hdrbuf, "\n")) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (NULL); } (void) fclose(fp); } if (cat_and_count(&hdrbuf, HDR_SUFFIX) || cat_and_count(&hdrbuf, "\n")) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MEM)); (void) fclose(fp); ecleanup(); return (NULL); } return (&hdrbuf); }
int esystem(char *cmd, int ifd, int ofd) { char *perrfile; int status = 0; pid_t pid; perrfile = tmpnam(NULL); if (perrfile == NULL) { progerr( pkg_gt("unable to create temp error file, errno=%d"), errno); return (-1); } (void) strlcpy(errfile, perrfile, sizeof (errfile)); /* flush standard i/o before creating new process */ (void) fflush(stderr); (void) fflush(stdout); /* * create new process to execute command in; * vfork() is being used to avoid duplicating the parents * memory space - this means that the child process may * not modify any of the parents memory including the * standard i/o descriptors - all the child can do is * adjust interrupts and open files as a prelude to a * call to exec(). */ pid = vfork(); if (pid == 0) { /* * this is the child process */ int i; /* reset any signals to default */ for (i = 0; i < NSIG; i++) { (void) sigset(i, SIG_DFL); } if (ifd > 0) { (void) dup2(ifd, STDIN_FILENO); } if (ofd >= 0 && ofd != STDOUT_FILENO) { (void) dup2(ofd, STDOUT_FILENO); } i = open(errfile, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (i >= 0) { dup2(i, STDERR_FILENO); } /* Close all open files except standard i/o */ closefrom(3); /* execute target executable */ execl("/sbin/sh", "/sbin/sh", "-c", cmd, NULL); progerr(pkg_gt("exec of <%s> failed, errno=%d"), cmd, errno); _exit(99); } else if (pid < 0) { /* fork failed! */ logerr(pkg_gt("bad vfork(), errno=%d"), errno); return (-1); } /* * this is the parent process */ sighold(SIGINT); pid = waitpid(pid, &status, 0); sigrelse(SIGINT); if (pid < 0) { return (-1); /* probably interrupted */ } switch (status & 0177) { case 0: case 0177: status = status >> 8; /*FALLTHROUGH*/ default: /* terminated by a signal */ status = status & 0177; } if (status == 0) { ecleanup(); } return (status); }