/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * System includes */ #include #include #include #include #include #include #include #include #include #include #include #include /* * consolidation pkg command library includes */ #include /* * local pkg command library includes */ #include "libadm.h" #include "libinst.h" #include "install.h" #include "messages.h" #include "pkginstall.h" /* * forward declarations */ static int write_file(char **r_linknam, int a_ctrl, mode_t a_mode, char *a_file); static int create_path(int a_ctrl, char *a_file); /* * Name: cppath * Description: copy a path object (install new file on system) * Arguments: * - a_cntrl - determine how the destination file mode is set: * |= MODE_0666 - force mode to 0666 * |= MODE_SET - mode is a_mode (no mask SET?ID bits) * |= MODE_SRC - mode from source file (mask SET?ID bits) * |= DIR_DISPLAY - display "%s " if directory created * - a_srcPath - path to source to copy * - a_dstPath - path to copy source to * - a_mode - mode to set a_dstpath to (mode controlled by a_ctrl) * Returns: int * == 0 - success * != 0 - failure */ int cppath(int a_ctrl, char *a_srcPath, char *a_dstPath, mode_t a_mode) { char *linknam = (char *)NULL; int dstFd; int len; int srcFd; long status; struct stat srcStatbuf; struct utimbuf times; /* entry debugging info */ echoDebug(DBG_CPPATH_ENTRY, a_ctrl, a_mode, a_srcPath, a_dstPath); /* open source file for reading */ srcFd = open(a_srcPath, O_RDONLY); if (srcFd < 0) { progerr(ERR_OPEN_READ, a_srcPath, errno, strerror(errno)); return (1); } /* obtain file status of source file */ if (fstat(srcFd, &srcStatbuf) != 0) { progerr(ERR_FSTAT, srcFd, a_srcPath, errno, strerror(errno)); (void) close(srcFd); return (1); } /* * Determine the permissions mode for the destination: * - if MODE_SET is specified: * --> use a_mode (do not mask off any portion) * --> If a_mode is unknown (? in the pkgmap), then the file gets * --> installed with the default 0644 mode * - if MODE_SRC is specified: * --> use the mode of the source (srcStatbuf.st_mode) but mask off all * --> non-access mode bits (remove SET?UID bits) * - otherwise: * --> use 0666 */ if (a_ctrl & MODE_SET) { mode_t usemode; usemode = (a_mode ^ BADMODE) ? a_mode : 0644; if (a_mode != usemode && usemode == 0644) { logerr(WRN_DEF_MODE, a_dstPath); a_mode = usemode; } } else if (a_ctrl & MODE_SRC) { a_mode = (srcStatbuf.st_mode & S_IAMB); } else { a_mode = 0666; } /* * Get fd of newly created destination file or, if this * is an overwrite, a temporary file (linknam). */ dstFd = write_file(&linknam, a_ctrl, a_mode, a_dstPath); if (dstFd < 0) { (void) close(srcFd); return (1); } /* * source and target files are open: copy data */ status = copyFile(srcFd, dstFd, a_srcPath, a_dstPath, &srcStatbuf, 0); (void) close(srcFd); (void) close(dstFd); if (status != 0) { progerr(ERR_INPUT, a_srcPath, errno, strerror(errno)); if (linknam) { (void) remove(linknam); } return (1); } /* * If this is an overwrite, rename temp over original */ if ((linknam != (char *)NULL) && (rename(linknam, a_dstPath) != 0)) { FILE *logfp = (FILE *)NULL; char busylog[PATH_MAX]; /* output log message if busy else program error */ if (errno == ETXTBSY) { logerr(MSG_PROCMV, linknam); } else { progerr(ERR_OUTPUT_WRITING, a_dstPath, errno, strerror(errno)); } (void) remove(linknam); /* open the log file and append log entry */ len = snprintf(busylog, sizeof (busylog), "%s/textbusy", get_PKGADM()); if (len > sizeof (busylog)) { progerr(ERR_CREATE_PATH_2, get_PKGADM(), "textbusy"); } else { logfp = fopen(busylog, "a"); if (logfp == NULL) { progerr(ERR_LOG, busylog, errno, strerror(errno)); } else { (void) fprintf(logfp, "%s\n", linknam); (void) fclose(logfp); } } } /* set access/modification times for target */ times.actime = srcStatbuf.st_atime; times.modtime = srcStatbuf.st_mtime; if (utime(a_dstPath, ×) != 0) { progerr(ERR_MODTIM, a_dstPath, errno, strerror(errno)); return (1); } /* success! */ return (0); } /* * This function creates all of the directory components of the specified path. */ static int create_path(int a_ctrl, char *a_file) { char *pt; int found = 0; for (pt = a_file; *pt; pt++) { /* continue if not at path separator or at start of path */ if ((*pt != '/') || (pt == a_file)) { continue; } /* at '/' - terminate path at current entry */ *pt = '\0'; /* continue if path element exists */ if (access(a_file, F_OK) == 0) { *pt = '/'; continue; } /* create directory in path */ if (mkdir(a_file, 0755)) { progerr(ERR_MAKE_DIR, a_file, errno, strerror(errno)); *pt = '/'; return (1); } /* display 'implied directory created' message */ if (a_ctrl & DIR_DISPLAY) { echo(MSG_IMPDIR, a_file); } found++; *pt = '/'; } return (!found); } /* * Name: write_file * Description: creates a new destination file if the file does not already * exist; otherwise, creates a temporary file and places a * pointer to the temporary file name in 'r_linknam'. * Arguments: r_linknam - pointer to (char*) where name of temporary file * created is returned * a_ctrl - determine if the destination file name is displayed: * |= DIR_DISPLAY - display "%s " * if directory created * a_mode - permissions mode to set a_file to * a_file - name of destination file to open * Returns: int * success - file descriptor of the file it opened. * failure - returns -1 */ static int write_file(char **r_linknam, int a_ctrl, mode_t a_mode, char *a_file) { int len; int fd = -1; static char loc_link[PATH_MAX]; /* entry debugging */ echoDebug(DBG_WRITEFILE_ENTRY, a_ctrl, a_mode, a_file); /* reset pointer to returned 'temporary file name' */ *r_linknam = (char *)NULL; /* * If we are overwriting an existing file, arrange to replace * it transparently. */ if (access(a_file, F_OK) == 0) { /* * link the file to be copied to a temporary name in case * it is executing or it is being written/used (e.g., a shell * script currently being executed */ if (!RELATIVE(a_file)) { len = snprintf(loc_link, sizeof (loc_link), "%sXXXXXX", a_file); if (len > sizeof (loc_link)) { progerr(ERR_CREATE_PATH_2, a_file, "XXXXXX"); } } else { logerr(WRN_RELATIVE, a_file); len = snprintf(loc_link, sizeof (loc_link), "./%sXXXXXX", a_file); if (len > sizeof (loc_link)) { progerr(ERR_CREATE_PATH_3, "./", a_file, "XXXXXX"); } } /* create and open temporary file */ fd = mkstemp(loc_link); if (fd == -1) { progerr(ERR_MKTEMP, loc_link, errno, strerror(errno)); return (-1); } /* remember name of temporary file */ *r_linknam = loc_link; /* make sure temporary file has correct mode */ if (fchmod(fd, a_mode) < 0) { progerr(ERR_FCHMOD, loc_link, a_mode, errno, strerror(errno)); } return (fd); } /* * We are not overwriting an existing file, create a new one directly. */ fd = open(a_file, O_WRONLY | O_CREAT | O_TRUNC, a_mode); if (fd == -1) { if (create_path(a_ctrl, a_file) == 0) { fd = open(a_file, O_WRONLY | O_CREAT | O_TRUNC, a_mode); } } if (fd == -1) { progerr(ERR_OPEN_WRITE, a_file, errno, strerror(errno)); } return (fd); }