예제 #1
0
static int
pkgxfer(char *srcinst, int options)
{
	int	r;
	struct pkginfo info;
	FILE	*fp, *pp;
	char	*pt, *src, *dst;
	char	dstdir[PATH_MAX],
		temp[PATH_MAX],
		srcdir[PATH_MAX],
		cmd[CMDSIZE],
		pkgname[NON_ABI_NAMELNGTH];
	int	i, n, part, nparts, maxpartsize, curpartcnt, iscomp;
	char	volnos[128], tmpvol[128];
	struct	statvfs64 svfsb;
	longlong_t 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) strlcpy(dstinst, srcinst, sizeof (dstinst));

	if (!(options & PT_ODTSTREAM)) {
		/* destination is a (possibly mounted) directory */
		(void) snprintf(dstdir, sizeof (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) strlcpy(temp, srcinst, sizeof (temp));
		if (pt = strchr(temp, '.'))
			*pt = '\0';
		(void) strlcat(temp, ".*", sizeof (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) strlcpy(dstinst, pt, sizeof (dstinst));
				(void) snprintf(dstdir, sizeof (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) snprintf(dstinst, sizeof (dstinst),
				    "%s.%d", temp, i);
				(void) snprintf(dstdir, sizeof (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) snprintf(srcdir, sizeof (srcdir),
		    "%s/%s", src, srcinst);
		if (stat(srcdir, &srcstat) != -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) snprintf(srcdir, sizeof (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) snprintf(cmd, sizeof (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);

		(void) sighold(SIGINT);
		(void) sighold(SIGHUP);
		r = epclose(pp);
		(void) sigrelse(SIGINT);
		(void) sigrelse(SIGHUP);

		if (r != 0) {
			rpterr();
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_PCLOSE), cmd, errno);
			return (1);
		}

		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");

					(void) sighold(SIGINT);
					(void) sighold(SIGHUP);
					r = epclose(pp);
					(void) sigrelse(SIGINT);
					(void) sigrelse(SIGHUP);

					if (r != 0) {
						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;
		/* LINTED E_SEC_SCANF_UNBOUNDED_COPY */
		if (sscanf(line, "%s %d %d %[ 0-9]", pkgname, &nparts,
		    &maxpartsize, volnos) == 4) {
			(void) sscanf(volnos,
			    "%d %[ 0-9]", &curpartcnt, tmpvol);
			(void) strlcpy(volnos, tmpvol, sizeof (volnos));
		}
	}

	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, O_WRONLY)) < 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) strlcpy(volnos, tmpvol, sizeof (volnos));
			curpartcnt += index;
		}

		if (options & PT_INFO_ONLY)
			nparts = 0;

		if (part == 1) {
			(void) snprintf(cmd, sizeof (cmd),
			    "find %s %s", PKGINFO, PKGMAP);
			if (nparts && (isdir(INSTALL) == 0)) {
				(void) strlcat(cmd, " ", sizeof (cmd));
				(void) strlcat(cmd, INSTALL, sizeof (cmd));
			}
		} else
			(void) snprintf(cmd, sizeof (cmd), "find %s", PKGINFO);

		if (nparts > 1) {
			(void) snprintf(temp, sizeof (temp),
			    "%s.%d", RELOC, part);
			if (iscpio(temp, &iscomp) || isdir(temp) == 0) {
				(void) strlcat(cmd, " ", sizeof (cmd));
				(void) strlcat(cmd, temp, sizeof (cmd));
			}
			(void) snprintf(temp, sizeof (temp),
			    "%s.%d", ROOT, part);
			if (iscpio(temp, &iscomp) || isdir(temp) == 0) {
				(void) strlcat(cmd, " ", sizeof (cmd));
				(void) strlcat(cmd, temp, sizeof (cmd));
			}
			(void) snprintf(temp, sizeof (temp),
			    "%s.%d", ARCHIVE, part);
			if (isdir(temp) == 0) {
				(void) strlcat(cmd, " ", sizeof (cmd));
				(void) strlcat(cmd, temp, sizeof (cmd));
			}
		} else if (nparts) {
			for (i = 0; reloc_names[i] != NULL; i++) {
				if (iscpio(reloc_names[i], &iscomp) ||
				    isdir(reloc_names[i]) == 0) {
					(void) strlcat(cmd, " ", sizeof (cmd));
					(void) strlcat(cmd, reloc_names[i],
					    sizeof (cmd));
				}
			}
			for (i = 0; root_names[i] != NULL; i++) {
				if (iscpio(root_names[i], &iscomp) ||
				    isdir(root_names[i]) == 0) {
					(void) strlcat(cmd, " ", sizeof (cmd));
					(void) strlcat(cmd, root_names[i],
					    sizeof (cmd));
				}
			}
			if (isdir(ARCHIVE) == 0) {
				(void) strlcat(cmd, " ", sizeof (cmd));
				(void) strlcat(cmd, ARCHIVE, sizeof (cmd));
			}
		}
		if (options & PT_ODTSTREAM) {
			(void) snprintf(cmd + strlen(cmd),
			    sizeof (cmd) - strlen(cmd),
			    " -print | %s -ocD -C %d",
			    CPIOPROC, (int)BLK_SIZE);
		} else {
			if (statvfs64(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),
				    has_comp_size ?
				    (long)compressedsize : (long)maxpartsize,
				    free_blocks);
				return (1);
			}
			(void) snprintf(cmd + strlen(cmd),
			    sizeof (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));
					(void) chdir("/");
					(void) pkgumount(&srcdev);
					continue;
				}
				if (ckvolseq(srcdir, part, nparts)) {
					(void) chdir("/");
					(void) 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) strlcpy(volnos, tmpvol, sizeof (volnos));
				curpartcnt += index;
			}
		}

	}
	return (0);
}
예제 #2
0
/*
 * Name:	compute_checksum
 * Description:	generate checksum for specified file
 * Arguments:	r_cksumerr (int *) [RO, *RW]
 *			- pointer to integer that is set on return to:
 *				== 0 - no error occurred
 *				!= 0 - error occurred
 *		a_path (char *) [RO, *RO]
 *			- pointer to string representing path to file to
 *			  generate checksum of
 * Returns:	unsigned long - results:
 *			- If *r_cksumerr == 0, checksum of specified file
 *			- If *r_cksumerr != 0, undefined
 */
unsigned long
compute_checksum(int *r_cksumerr, char *a_path)
{
	CHECKSUM_T	suma;	/* to split four-bytes into 2 two-byte values */
	CHECKSUM_T	tempa;
	int		fd;
	uint32_t	lg;	/* running checksum value */
	uint32_t	buf[CHUNK/4]; /* to read CHUNK bytes */
	uint32_t	lsavhi;	/* high order two-bytes of four-byte checksum */
	uint32_t	lsavlo;	/* low order two-bytes of four-byte checksum */
	int		leap = sizeof (uint32_t);
	int		notyet = 0;
	int		nread;
	struct stat64	sbuf;

	/* reset error flag */
	*r_cksumerr = 0;

	/* open file and obtain -> where file is mapped/read */
	if ((fd = open(a_path, O_RDONLY)) < 0) {
		*r_cksumerr = 1;
		reperr(pkg_gt(ERR_NO_CKSUM));
		perror(ERR_NO_CKSUM);
		return (0);
	}

	if (fstat64(fd, &sbuf) != 0) {
		*r_cksumerr = 1;
		reperr(pkg_gt(ERR_NO_CKSUM));
		perror(ERR_NO_CKSUM);
		return (0);
	}

	/* initialize checksum value */
	lg = 0;

	/*
	 * Read CHUNK bytes off the file at a time; Read size of long bytes
	 * from memory at a time and process them.
	 * If last read, then read remnant bytes and process individually.
	 */
	errno = 0;
	while ((nread = read(fd, (void*)buf,
		    (sbuf.st_size < CHUNK) ? sbuf.st_size : CHUNK)) > 0) {
		uchar_t *s;
		uint32_t *p = buf;

		notyet = nread % leap;
		nread -= notyet;

		for (; nread > 0; nread -= leap) {
			lg += ((((*p)>>24)&0xFF) & WDMSK);
			lg += ((((*p)>>16)&0xFF) & WDMSK);
			lg += ((((*p)>>8)&0xFF) & WDMSK);
			lg += (((*p)&0xFF) & WDMSK);
			p++;
		}
		s = (uchar_t *)p;
		/* leftover bytes less than four in number */
		while (notyet--)
			lg += (((uint32_t)(*s++)) & WDMSK);
	}

	/* wind up */
	(void) close(fd);

	/* compute checksum components */
	suma.lg = lg;
	tempa.lg = (suma.hl.lo & WDMSK) + (suma.hl.hi & WDMSK);
	lsavhi = (uint32_t)tempa.hl.hi;
	lsavlo = (uint32_t)tempa.hl.lo;

	/* return final checksum value */
	return (lsavhi+lsavlo);
}
예제 #3
0
/*
 * Name:	averify
 * Description:	This function verifies and (if fix > 0) fixes the attributes
 *		of the file at the path provided.
 * Arguments:	fix - 0 - do not fix entries, 1 - fix entries
 *		ftype - single character "type" the entry is supposed to be
 *		path - path to file
 *		ainfo - attribute info structure representing the attributes
 *			the entry is supposed to be
 * NOTE:	attributes are links and permissions
 * Possible return values:
 * - 0 = successful
 * - VE_EXIST = path name does not exist
 * - VE_FTYPE = path file type is not recognized, is not supported,
 *		or is not what was expected
 * - VE_ATTR = path mode/group/user is not what was expected
 * - VE_CONT = mod time/link target/major/minor/size/file system type/current
 *		directory is not what was expected
 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/
 *		chown failed
 */
int
averify(int fix, char *ftype, char *path, struct ainfo *ainfo)
{
	struct group	*grp; 	/* group entry buffer */
	struct passwd	*pwd;
	int		n;
	int		setval;
	int		uid, gid;
	int		dochown;
	int		retcode;
	int		statError = 0;
	int		targ_is_dir = 0;	/* replacing a directory */
	char		myftype;
	char		buf[PATH_MAX];
	ino_t		my_ino;
	dev_t		my_dev;
	char 		cwd[MAXPATHLEN];
	char 		*cd;
	char 		*c;

	setval = (*ftype == '?');
	retcode = 0;
	reperr(NULL);

	if (get_disable_attribute_check()) {
		return (0);
	}

	if (*ftype == 'l') {
		if (stat(path, &status) < 0) {
			retcode = VE_EXIST;
			reperr(pkg_gt(ERR_EXIST));
		}

		my_ino = status.st_ino;
		my_dev = status.st_dev;

		/* Get copy of the current working directory */
		if (getcwd(cwd, MAXPATHLEN) == NULL) {
			reperr(pkg_gt(ERR_GETWD));
			return (VE_FAIL);
		}

		/*
		 * Change to the directory in which the hard
		 * link is to be created.
		 */
		cd = strdup(path);
		c = strrchr(cd, '/');
		if (c) {
			/* bugid 4247895 */
			if (strcmp(cd, c) == 0)
				(void) strcpy(cd, "/");
			else
				*c = NULL;

			if (chdir(cd) != 0) {
				reperr(pkg_gt(ERR_CHDIR), cd);
				return (VE_FAIL);
			}
		}
		free(cd);

		if (retcode || (status.st_nlink < 2) ||
		    (stat(ainfo->local, &status) < 0) ||
		    (my_dev != status.st_dev) || (my_ino != status.st_ino)) {
			if (fix) {
				/*
				 * Don't want to do a hard link to a
				 * directory.
				 */
				if (!isdir(ainfo->local)) {
					(void) chdir(cwd);
					reperr(pkg_gt(ERR_LINKISDIR),
					    ainfo->local);
					return (VE_FAIL);
				}
				/* Now do the link. */
				if (!clear_target(path, ftype, targ_is_dir))
					return (VE_FAIL);

				if (link(ainfo->local, path)) {
					(void) chdir(cwd);
					reperr(pkg_gt(ERR_LINKFAIL),
					    ainfo->local);
					return (VE_FAIL);
				}
				retcode = 0;
			} else {
				/* Go back to previous working directory */
				if (chdir(cwd) != 0)
					reperr(pkg_gt(ERR_CHDIR), cwd);

				reperr(pkg_gt(ERR_LINK), ainfo->local);
				return (VE_CONT);
			}
		}

		/* Go back to previous working directory */
		if (chdir(cwd) != 0) {
			reperr(pkg_gt(ERR_CHDIR), cwd);
			return (VE_CONT);
		}

		return (retcode);
	}

	retcode = 0;

	/* If we are to process symlinks the old way then we follow the link */
	if (nonABI_symlinks()) {
		if ((*ftype == 's') ? lstat(path, &status) :
			stat(path, &status)) {
			reperr(pkg_gt(ERR_EXIST));
			retcode = VE_EXIST;
			myftype = '?';
			statError++;
		}
	/* If not then we inspect the target of the link */
	} else {
		if ((n = lstat(path, &status)) == -1) {
			reperr(pkg_gt(ERR_EXIST));
			retcode = VE_EXIST;
			myftype = '?';
			statError++;
		}
	}
	if (!statError) {
		/* determining actual type of existing object */
		switch (status.st_mode & S_IFMT) {
		    case S_IFLNK:
			myftype = 's';
			break;

		    case S_IFIFO:
			myftype = 'p';
			break;

		    case S_IFCHR:
			myftype = 'c';
			break;

		    case S_IFDIR:
			myftype = 'd';
			targ_is_dir = 1;
			break;

		    case S_IFBLK:
			myftype = 'b';
			break;

		    case S_IFREG:
		    case 0:
			myftype = 'f';
			break;

		    case S_IFDOOR:
			myftype = 'D';
			break;

		    default:
			reperr(pkg_gt(ERR_UNKNOWN));
			return (VE_FTYPE);
		}
	}

	if (setval) {
		/*
		 * Check to make sure that a package or an installf that uses
		 * wild cards '?' to assume the ftype of an object on the
		 * system is not assuming a door ftype. Doors are not supported
		 * but should be ignored.
		 */
		if (myftype == 'D') {
			reperr(pkg_gt(ERR_FTYPED), path);
			retcode = VE_FTYPE;
			return (VE_FTYPE);
		} else {
			*ftype = myftype;
		}
	} else if (!retcode && (*ftype != myftype) &&
	    ((myftype != 'f') || !strchr("ilev", *ftype)) &&
	    ((myftype != 'd') || (*ftype != 'x'))) {
		reperr(pkg_gt(ERR_FTYPE), *ftype, myftype);
		retcode = VE_FTYPE;
	}

	if (!retcode && (*ftype == 's')) {
		/* make sure that symbolic link is correct */
		n = readlink(path, buf, PATH_MAX);
		if (n < 0) {
			reperr(pkg_gt(ERR_SLINK), ainfo->local);
			retcode = VE_CONT;
		} else if (ainfo->local != NULL) {
			buf[n] = '\0';
			if (strcmp(buf, ainfo->local)) {
				reperr(pkg_gt(ERR_SLINK), ainfo->local);
				retcode = VE_CONT;
			}
		} else if (ainfo->local == NULL) {
			/*
			 * Since a sym link target exists, insert it
			 * into the ainfo structure
			 */
			buf[n] = '\0';
			ainfo->local = strdup(buf);
		}
	}

	if (retcode) {
		/* The path doesn't exist or is different than it should be. */
		if (fix) {
			/*
			 * Clear the way for the write. If it won't clear,
			 * there's nothing we can do.
			 */
			if (!clear_target(path, ftype, targ_is_dir))
				return (VE_FAIL);

			if ((*ftype == 'd') || (*ftype == 'x')) {
				char	*pt, *p;

				/* Try to make it the easy way */
				if (mkdir(path, ainfo->mode)) {
					/*
					 * Failing that, walk through the
					 * parent directories creating
					 * whatever is needed.
					 */
					p = strdup(path);
					pt = (*p == '/') ? p+1 : p;
					do {
						if (pt = strchr(pt, '/'))
							*pt = '\0';
						if (access(p, 0) &&
						    mkdir(p, ainfo->mode))
							break;
						if (pt)
							*pt++ = '/';
					} while (pt);
					free(p);
				}
				if (stat(path, &status) < 0) {
					reperr(pkg_gt(ERR_DIRFAIL));
					return (VE_FAIL);
				}
			} else if (*ftype == 's') {
				if (symlink(ainfo->local, path)) {
					reperr(pkg_gt(ERR_SLINKFAIL),
					    ainfo->local);
					return (VE_FAIL);
				}

			} else if (*ftype == 'c') {
				int wilddevno = 0;
				/*
				 * The next three if's support 2.4 and older
				 * packages that use "?" as device numbers.
				 * This should be considered for removal by
				 * release 2.7 or so.
				 */
				if (ainfo->major == BADMAJOR) {
					ainfo->major = 0;
					wilddevno = 1;
				}

				if (ainfo->minor == BADMINOR) {
					ainfo->minor = 0;
					wilddevno = 1;
				}

				if (wilddevno) {
					wilddevno = 0;
					logerr(MSG_WLDDEVNO, path,
					    ainfo->major, ainfo->minor);
				}

				if (mknod(path, ainfo->mode | S_IFCHR,
				    makedev(ainfo->major, ainfo->minor)) ||
				    (stat(path, &status) < 0)) {
					reperr(pkg_gt(ERR_CDEVFAIL));
					return (VE_FAIL);
				}
			} else if (*ftype == 'b') {
				int wilddevno = 0;
				/*
				 * The next three if's support 2.4 and older
				 * packages that use "?" as device numbers.
				 * This should be considered for removal by
				 * release 2.7 or so.
				 */
				if (ainfo->major == BADMAJOR) {
					ainfo->major = 0;
					wilddevno = 1;
				}

				if (ainfo->minor == BADMINOR) {
					ainfo->minor = 0;
					wilddevno = 1;
				}

				if (wilddevno) {
					wilddevno = 0;
					logerr(MSG_WLDDEVNO, path,
					    ainfo->major, ainfo->minor);
				}

				if (mknod(path, ainfo->mode | S_IFBLK,
				    makedev(ainfo->major, ainfo->minor)) ||
				    (stat(path, &status) < 0)) {
					reperr(pkg_gt(ERR_BDEVFAIL));
					return (VE_FAIL);
				}
			} else if (*ftype == 'p') {
				if (mknod(path, ainfo->mode | S_IFIFO, NULL) ||
				    (stat(path, &status) < 0)) {
					reperr(pkg_gt(ERR_PIPEFAIL));
					return (VE_FAIL);
				}
			} else
				return (retcode);

		} else
			return (retcode);
	}

	if (*ftype == 's')
		return (0); /* don't check anything else */
	if (*ftype == 'i')
		return (0); /* don't check anything else */

	retcode = 0;
	if ((myftype == 'c') || (myftype == 'b')) {
		if (setval || (ainfo->major == BADMAJOR))
			ainfo->major = major(status.st_rdev);
		if (setval || (ainfo->minor == BADMINOR))
			ainfo->minor = minor(status.st_rdev);
		/* check major & minor */
		if (status.st_rdev != makedev(ainfo->major, ainfo->minor)) {
			reperr(pkg_gt(ERR_MAJMIN), ainfo->major, ainfo->minor,
			    major(status.st_rdev), minor(status.st_rdev));
			retcode = VE_CONT;
		}
	}

	/* compare specified mode w/ actual mode excluding sticky bit */
	if (setval || (ainfo->mode == BADMODE) || (ainfo->mode == WILDCARD))
		ainfo->mode = status.st_mode & 07777;
	else if ((ainfo->mode & 06777) != (status.st_mode & 06777)) {
		if (fix) {
			if ((ainfo->mode == BADMODE) ||
			    (chmod(path, ainfo->mode) < 0))
				retcode = VE_FAIL;
		} else {
			reperr(pkg_gt(ERR_PERM), ainfo->mode,
				status.st_mode & 07777);
			if (!retcode)
				retcode = VE_ATTR;
		}
	}

	dochown = 0;

	/* get group entry for specified group */
	if (setval || strcmp(ainfo->group, BADGROUP) == 0) {
		grp = cgrgid(status.st_gid);
		if (grp)
			(void) strcpy(ainfo->group, grp->gr_name);
		else {
			if (!retcode)
				retcode = VE_ATTR;
			reperr(pkg_gt(ERR_BADGRPID), status.st_gid);
		}
		gid = status.st_gid;
	} else if ((grp = cgrnam(ainfo->group)) == NULL) {
		reperr(pkg_gt(ERR_BADGRPNM), ainfo->group);
		if (!retcode)
			retcode = VE_ATTR;
	} else if ((gid = grp->gr_gid) != status.st_gid) {
		if (fix) {
			/* save specified GID */
			gid = grp->gr_gid;
			dochown++;
		} else {
			if ((grp = cgrgid((int)status.st_gid)) ==
			    (struct group *)NULL) {
				reperr(pkg_gt(ERR_GROUP), ainfo->group,
				    "(null)");
			} else {
				reperr(pkg_gt(ERR_GROUP), ainfo->group,
				    grp->gr_name);
			}
			if (!retcode)
				retcode = VE_ATTR;
		}
	}

	/* get password entry for specified owner */
	if (setval || strcmp(ainfo->owner, BADOWNER) == 0) {
		pwd = cpwuid((int)status.st_uid);
		if (pwd)
			(void) strcpy(ainfo->owner, pwd->pw_name);
		else {
			if (!retcode)
				retcode = VE_ATTR;
			reperr(pkg_gt(ERR_BADUSRID), status.st_uid);
		}
		uid = status.st_uid;
	} else if ((pwd = cpwnam(ainfo->owner)) == NULL) {
		/* UID does not exist in password file */
		reperr(pkg_gt(ERR_BADUSRNM), ainfo->owner);
		if (!retcode)
			retcode = VE_ATTR;
	} else if ((uid = pwd->pw_uid) != status.st_uid) {
		/* get owner name for actual UID */
		if (fix) {
			uid = pwd->pw_uid;
			dochown++;
		} else {
			pwd = cpwuid((int)status.st_uid);
			if (pwd == NULL)
				reperr(pkg_gt(ERR_BADUSRID),
				    (int)status.st_uid);
			else
				reperr(pkg_gt(ERR_OWNER), ainfo->owner,
				    pwd->pw_name);

			if (!retcode)
				retcode = VE_ATTR;
		}
	}

	if (statvfs(path, &vfsstatus) < 0) {
		reperr(pkg_gt(ERR_EXIST));
		retcode = VE_FAIL;
	} else {
		if (dochown) {
			/* pcfs doesn't support file ownership */
			if (strcmp(vfsstatus.f_basetype, "pcfs") != 0 &&
			    chown(path, uid, gid) < 0) {
				retcode = VE_FAIL; /* chown failed */
			}
		}
	}

	if (retcode == VE_FAIL)
		reperr(pkg_gt(ERR_ATTRFAIL));
	return (retcode);
}
예제 #4
0
int
cverify(int fix, char *ftype, char *path, struct cinfo *cinfo,
	int allow_checksum)
{
	struct stat	status; 	/* file status buffer */
	struct utimbuf	times;
	unsigned long	mycksum;
	int		setval, retcode;
	char		tbuf1[512];
	char		tbuf2[512];
	int		cksumerr;

	setval = (*ftype == '?');
	retcode = 0;
	reperr(NULL);

	if (stat(path, &status) < 0) {
		reperr(pkg_gt(ERR_EXIST));
		return (VE_EXIST);
	}

	/* -1	requires modtimes to be the same */
	/*  0   reports modtime failure */
	/*  1   fixes modtimes */

	if (setval || (cinfo->modtime == BADCONT)) {
		cinfo->modtime = status.st_mtime;
	} else if (status.st_mtime != cinfo->modtime) {
		if (fix > 0) {
			/* reset times on the file */
			times.actime = cinfo->modtime;
			times.modtime = cinfo->modtime;
			if (utime(path, &times)) {
				reperr(pkg_gt(ERR_MODFAIL));
				retcode = VE_FAIL;
			}
		} else if (fix < 0) {
			/* modtimes must be the same */
			if (strftime(tbuf1, sizeof (tbuf1), DATEFMT,
				localtime(&cinfo->modtime)) == 0) {
				reperr(pkg_gt(ERR_MEM));
			}
			if (strftime(tbuf2, sizeof (tbuf2), DATEFMT,
				localtime(&status.st_mtime)) == 0) {
				reperr(pkg_gt(ERR_MEM));
			}
			reperr(pkg_gt(ERR_MTIME), tbuf1, tbuf2);
			retcode = VE_CONT;
		}
	}

	if (setval || (cinfo->size == (fsblkcnt_t)BADCONT)) {
		cinfo->size = status.st_size;
	} else if (status.st_size != cinfo->size) {
		if (!retcode) {
			retcode = VE_CONT;
		}
		reperr(pkg_gt(ERR_SIZE), cinfo->size, status.st_size);
	}

	cksumerr = 0;

	/*
	 * see if checksumming should be done: if checksumming is allowed,
	 * and checksumming is enabled, then checksum the file.
	 */

	/* return if no need to compute checksum */

	if ((allow_checksum == 0) || (enable_checksum == 0)) {
		return (retcode);
	}

	/* compute checksum */

	mycksum = compute_checksum(&cksumerr, path);

	/* set value if not set or if checksum cannot be computed */

	if (setval || (cinfo->cksum == BADCONT)) {
		cinfo->cksum = mycksum;
		return (retcode);
	}

	/* report / return error if checksums mismatch or there is an error */

	if ((mycksum != cinfo->cksum) || cksumerr) {
		if (!retcode) {
			retcode = VE_CONT;
		}
		if (!cksumerr) {
			reperr(pkg_gt(ERR_CKSUM), cinfo->cksum, mycksum);
		}
	}

	return (retcode);
}
예제 #5
0
int
pkgmount(struct pkgdev *devp, char *pkg, int part, int nparts, int getvolflg)
{
	int	n;
	char	*pt, prompt[64], cmd[CMDSIZ];
	FILE	*pp;

	if (getuid()) {
		progerr(pkg_gt(ERR_NOTROOT));
		return (99);
	}

	if (part && nparts) {
		if (pkg) {
			(void) snprintf(prompt, sizeof (prompt),
			    pkg_gt(LABEL0), part, nparts, pkg);
		} else {
			(void) snprintf(prompt, sizeof (prompt),
			    pkg_gt(LABEL1), part, nparts);
		}
	} else if (pkg)
		(void) snprintf(prompt, sizeof (prompt), pkg_gt(LABEL2), pkg);
	else
		(void) snprintf(prompt, sizeof (prompt), pkg_gt(LABEL3));

	n = 0;
	for (;;) {
		if (!getvolflg && n)
			/*
			 * Return to caller if not prompting
			 * and error was encountered.
			 */
			return (-1);
		if (getvolflg && (n = getvol(devp->bdevice, NULL,
		    (devp->rdonly ? 0 : DM_FORMFS|DM_WLABEL), prompt))) {
			if (n == 3)
				return (3);
			if (n == 2)
				progerr(pkg_gt("unknown device <%s>"),
				    devp->bdevice);
			else
				progerr(
				    pkg_gt("unable to obtain package volume"));
			return (99);
		}

		if (devp->fstyp == NULL) {
			(void) snprintf(cmd, sizeof (cmd),
			    "%s %s", FSTYP, devp->bdevice);
			if ((pp = epopen(cmd, "r")) == NULL) {
				rpterr();
				logerr(pkg_gt(ERR_FSTYP), devp->bdevice);
				n = -1;
				continue;
			}
			cmd[0] = '\0';
			if (fgets(cmd, CMDSIZ, pp) == NULL) {
				logerr(pkg_gt(ERR_FSTYP), devp->bdevice);
				(void) pclose(pp);
				n = -1;
				continue;
			}
			if (epclose(pp)) {
				rpterr();
				logerr(pkg_gt(ERR_FSTYP), devp->bdevice);
				n = -1;
				continue;
			}
			if (pt = strpbrk(cmd, " \t\n"))
				*pt = '\0';
			if (cmd[0] == '\0') {
				logerr(pkg_gt(ERR_FSTYP), devp->bdevice);
				n = -1;
				continue;
			}
			devp->fstyp = strdup(cmd);
		}

		if (devp->rdonly) {
			n = pkgexecl(NULL, NULL, NULL, NULL, MOUNT, "-r", "-F",
			    devp->fstyp, devp->bdevice, devp->mount, NULL);
		} else {
			n = pkgexecl(NULL, NULL, NULL, NULL, MOUNT, "-F",
			    devp->fstyp, devp->bdevice, devp->mount, NULL);
		}
		if (n) {
			progerr(pkg_gt("mount of %s failed"), devp->bdevice);
			continue;
		}
		devp->mntflg++;
		break;
	}
	return (0);
}
예제 #6
0
int
pkgexecv(char *filein, char *fileout, char *uname, char *gname, char *arg[])
{
	int			exit_no;
	int			n;
	int			status;
	pid_t			pid;
	pid_t			waitstat;
	struct group		*grp;
	struct passwd		*pwp;
	struct sigaction	nact;
	struct sigaction	oact;
	void			(*funcSighup)(int);
	void			(*funcSigint)(int);

	/* flush standard i/o before creating new process */

	(void) fflush(stdout);
	(void) fflush(stderr);

	/*
	 * hold SIGINT/SIGHUP signals and reset signal received counter;
	 * after the vfork() the parent and child need to setup their respective
	 * interrupt handling and release the hold on the signals
	 */

	(void) sighold(SIGINT);
	(void) sighold(SIGHUP);

	sig_received = 0;

	/*
	 * 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) {
		/*
		 * *************************************************************
		 * fork failed!
		 * *************************************************************
		 */

		progerr(pkg_gt(ERR_FORK_FAILED), errno, strerror(errno));

		/* release hold on signals */

		(void) sigrelse(SIGHUP);
		(void) sigrelse(SIGINT);

		return (-1);
	}

	if (pid > 0) {
		/*
		 * *************************************************************
		 * This is the forking (parent) process
		 * *************************************************************
		 */

		/* close datastream if any portion read */

		if (ds_curpartcnt >= 0) {
			if (ds_close(0) != 0) {
				/* kill child process */

				(void) sigsend(P_PID, pid, SIGKILL);

				/* release hold on signals */

				(void) sigrelse(SIGHUP);
				(void) sigrelse(SIGINT);

				return (-1);
			}
		}

		/*
		 * setup signal handlers for SIGINT and SIGHUP and release hold
		 */

		/* hook SIGINT to sig_trap() */

		nact.sa_handler = sig_trap;
		nact.sa_flags = SA_RESTART;
		(void) sigemptyset(&nact.sa_mask);

		if (sigaction(SIGINT, &nact, &oact) < 0) {
			funcSigint = SIG_DFL;
		} else {
			funcSigint = oact.sa_handler;
		}

		/* hook SIGHUP to sig_trap() */

		nact.sa_handler = sig_trap;
		nact.sa_flags = SA_RESTART;
		(void) sigemptyset(&nact.sa_mask);

		if (sigaction(SIGHUP, &nact, &oact) < 0) {
			funcSighup = SIG_DFL;
		} else {
			funcSighup = oact.sa_handler;
		}

		/* release hold on signals */

		(void) sigrelse(SIGHUP);
		(void) sigrelse(SIGINT);

		/*
		 * wait for the process to exit, reap child exit status
		 */

		for (;;) {
			status = 0;
			waitstat = waitpid(pid, (int *)&status, 0);
			if (waitstat < 0) {
				/* waitpid returned error */
				if (errno == EAGAIN) {
					/* try again */
					continue;
				}
				if (errno == EINTR) {
					continue;
				}
				/* error from waitpid: bail */
				break;
			} else if (waitstat == pid) {
				/* child exit status available */
				break;
			}
		}

		/*
		 * reset signal handlers
		 */

		/* reset SIGINT */

		nact.sa_handler = funcSigint;
		nact.sa_flags = SA_RESTART;
		(void) sigemptyset(&nact.sa_mask);

		(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);

		/* reset SIGHUP */

		nact.sa_handler = funcSighup;
		nact.sa_flags = SA_RESTART;
		(void) sigemptyset(&nact.sa_mask);

		(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);

		/* error if child process does not match */

		if (waitstat != pid) {
			progerr(pkg_gt(ERR_WAIT_FAILED), pid, waitstat, status,
				errno, strerror(errno));
			return (-1);
		}

		/*
		 * determine final exit code:
		 * - if signal received, then return interrupted (3)
		 * - if child exit status is available, return exit child status
		 * - otherwise return error (-1)
		 */

		if (sig_received != 0) {
			exit_no = 3;	/* interrupted */
		} else if (WIFEXITED(status)) {
			exit_no = WEXITSTATUS(status);
		} else {
			exit_no = -1;	/* exec() or other process error */
		}

		return (exit_no);
	}

	/*
	 * *********************************************************************
	 * This is the forked (child) process
	 * *********************************************************************
	 */

	/* reset all signals to default */

	for (n = 0; n < NSIG; n++) {
		(void) sigset(n, SIG_DFL);
	}

	/* release hold on signals held by parent before fork() */

	(void) sigrelse(SIGHUP);
	(void) sigrelse(SIGINT);

	/*
	 * The caller wants to have stdin connected to filein.
	 */

	if (filein && *filein) {
		/*
		 * If input is supposed to be connected to /dev/tty
		 */
		if (strncmp(filein, "/dev/tty", 8) == 0) {
			/*
			 * If stdin is connected to a tty device.
			 */
			if (isatty(STDIN_FILENO)) {
				/*
				 * Reopen it to /dev/tty.
				 */
				n = open(filein, O_RDONLY);
				if (n >= 0) {
					(void) dup2(n, STDIN_FILENO);
				}
			}
		} else {
			/*
			 * If we did not want to be connected to /dev/tty, we
			 * connect input to the requested file no questions.
			 */
			n = open(filein, O_RDONLY);
			if (n >= 0) {
				(void) dup2(n, STDIN_FILENO);
			}
		}
	}

	/*
	 * The caller wants to have stdout and stderr connected to fileout.
	 * If "fileout" is "/dev/tty" then reconnect stdout to "/dev/tty"
	 * only if /dev/tty is not already associated with "a tty".
	 */

	if (fileout && *fileout) {
		/*
		 * If output is supposed to be connected to /dev/tty
		 */
		if (strncmp(fileout, "/dev/tty", 8) == 0) {
			/*
			 * If stdout is connected to a tty device.
			 */
			if (isatty(STDOUT_FILENO)) {
				/*
				 * Reopen it to /dev/tty if /dev/tty available.
				 */
				n = open(fileout, O_WRONLY);
				if (n >= 0) {
					/*
					 * /dev/tty is available - close the
					 * current standard output stream, and
					 * reopen it on /dev/tty
					 */
					(void) dup2(n, STDOUT_FILENO);
				}
			}
			/*
			 * not connected to tty device - probably redirect to
			 * file - preserve existing output device
			 */
		} else {
			/*
			 * If we did not want to be connected to /dev/tty, we
			 * connect output to the requested file no questions.
			 */
			/* LINTED O_CREAT without O_EXCL specified in call to */
			n = open(fileout, O_WRONLY|O_CREAT|O_APPEND, 0666);
			if (n >= 0) {
				(void) dup2(n, STDOUT_FILENO);
			}
		}

		/*
		 * Dup stderr from stdout.
		 */

		(void) dup2(STDOUT_FILENO, STDERR_FILENO);
	}

	/*
	 * do NOT close all file descriptors except stdio
	 * file descriptors are passed in to some subcommands
	 * (see dstream:ds_getinfo() and dstream:ds_putinfo())
	 */

	/* set group/user i.d. if requested */

	if (gname && *gname && (grp = cgrnam(gname)) != NULL) {
		if (setgid(grp->gr_gid) == -1) {
			progerr(pkg_gt(ERR_SETGID), grp->gr_gid);
		}
	}
	if (uname && *uname && (pwp = cpwnam(uname)) != NULL) {
		if (setuid(pwp->pw_uid) == -1) {
			progerr(pkg_gt(ERR_SETUID), pwp->pw_uid);
		}
	}

	/* execute target executable */

	(void) execve(arg[0], arg, environ);
	progerr(pkg_gt(ERR_EX_FAIL), arg[0], errno);
	_exit(99);
	/*NOTREACHED*/
}
예제 #7
0
파일: runcmd.c 프로젝트: belenix/belenixold
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);
}
예제 #8
0
/* will return 0, 1, 3, or 99 */
static int
_pkgtrans(char *device1, char *device2, char **pkg, int options,
    keystore_handle_t keystore, char *keystore_alias)
{
#ifdef	USE_KEYSTORE
	BIO			*p7_bio = NULL;
	EVP_PKEY		*privkey = NULL;
#endif
	PKCS7			*sec_pkcs7 = NULL;
#ifdef	USE_KEYSTORE
	PKCS7_SIGNER_INFO	*sec_signerinfo = NULL;
	PKG_ERR			*err;
	STACK_OF(X509)		*cacerts = NULL;
	STACK_OF(X509)		*clcerts = NULL;
	STACK_OF(X509)		*sec_chain = NULL;
	X509			*pubcert = NULL;
#endif
	boolean_t		making_sig = B_FALSE;
	char			*src, *dst;
	int			errflg, i, n;
	struct			dm_buf *hdr;

	making_sig = (keystore != NULL) ? B_TRUE : B_FALSE;

#ifdef	USE_KEYSTORE
	if (making_sig) {

		/* new error object */
		err = pkgerr_new();

		/* find matching cert and key */
		if (find_key_cert_pair(err, keystore,
		    keystore_alias, &privkey, &pubcert) != 0) {
			pkgerr(err);
			pkgerr_free(err);
			return (1);
		}

		/* get CA certificates */
		if (find_ca_certs(err, keystore, &cacerts) != 0) {
			pkgerr(err);
			pkgerr_free(err);
			return (1);
		}

		/* get CL (aka "chain") certificates */
		if (find_cl_certs(err, keystore, &clcerts) != 0) {
			pkgerr(err);
			pkgerr_free(err);
			return (1);
		}

		/* initialize PKCS7 object to be filled in later */
		sec_pkcs7 = PKCS7_new();
		PKCS7_set_type(sec_pkcs7, NID_pkcs7_signed);
		sec_signerinfo = PKCS7_add_signature(sec_pkcs7,
		    pubcert, privkey, EVP_sha1());

		if (sec_signerinfo == NULL) {
			progerr(gettext(ERR_SEC), keystore_alias);
			ERR_print_errors_fp(stderr);
			pkgerr_free(err);
			return (1);
		}

		/* add signer cert into signature */
		PKCS7_add_certificate(sec_pkcs7, pubcert);

		/* attempt to resolve cert chain starting at the signer cert */
		if (get_cert_chain(err, pubcert, clcerts, cacerts,
		    &sec_chain) != 0) {
			pkgerr(err);
			pkgerr_free(err);
			return (1);
		}

		/*
		 * add the verification chain of certs into the signature.
		 * The first cert is the user cert, which we don't need,
		 * since it's baked in already, so skip it
		 */
		for (i = 1; i < sk_X509_num(sec_chain); i++) {
			PKCS7_add_certificate(sec_pkcs7,
			    sk_X509_value(sec_chain, i));
		}

		pkgerr_free(err);
		err = NULL;
	}
#endif	/* USE_KEYSTORE */

	if (signal_received > 0) {
		return (1);
	}

	/* 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 (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) {
		char	template[] = "/var/tmp/ptXXXXXX";