Пример #1
0
/*
 * 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);
}
Пример #2
0
int
epclose(FILE *pp)
{
	int n;

	n = pclose(pp);
	if (n == 0)
		ecleanup();
	return (n);
}
Пример #3
0
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);
}
Пример #4
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);
}
Пример #5
0
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);
}