1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 /* 32 * System includes 33 */ 34 35 #include <stdio.h> 36 #include <string.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 #include <utime.h> 40 #include <locale.h> 41 #include <libintl.h> 42 #include <pkglocs.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 48 /* 49 * consolidation pkg command library includes 50 */ 51 52 #include <pkglib.h> 53 54 /* 55 * local pkg command library includes 56 */ 57 58 #include "libadm.h" 59 #include "libinst.h" 60 #include "install.h" 61 #include "messages.h" 62 #include "pkginstall.h" 63 64 /* 65 * forward declarations 66 */ 67 68 static int write_file(char **r_linknam, int a_ctrl, mode_t a_mode, 69 char *a_file); 70 static int create_path(int a_ctrl, char *a_file); 71 72 /* 73 * Name: cppath 74 * Description: copy a path object (install new file on system) 75 * Arguments: 76 * - a_cntrl - determine how the destination file mode is set: 77 * |= MODE_0666 - force mode to 0666 78 * |= MODE_SET - mode is a_mode (no mask SET?ID bits) 79 * |= MODE_SRC - mode from source file (mask SET?ID bits) 80 * |= DIR_DISPLAY - display "%s <implied directory>" if directory created 81 * - a_srcPath - path to source to copy 82 * - a_dstPath - path to copy source to 83 * - a_mode - mode to set a_dstpath to (mode controlled by a_ctrl) 84 * Returns: int 85 * == 0 - success 86 * != 0 - failure 87 */ 88 89 int 90 cppath(int a_ctrl, char *a_srcPath, char *a_dstPath, mode_t a_mode) 91 { 92 char *linknam = (char *)NULL; 93 int dstFd; 94 int len; 95 int srcFd; 96 long status; 97 struct stat srcStatbuf; 98 struct utimbuf times; 99 100 /* entry debugging info */ 101 102 echoDebug(DBG_CPPATH_ENTRY, a_ctrl, a_mode, a_srcPath, a_dstPath); 103 104 /* open source file for reading */ 105 106 srcFd = open(a_srcPath, O_RDONLY); 107 if (srcFd < 0) { 108 progerr(ERR_OPEN_READ, a_srcPath, 109 errno, strerror(errno)); 110 return (1); 111 } 112 113 /* obtain file status of source file */ 114 115 if (fstat(srcFd, &srcStatbuf) != 0) { 116 progerr(ERR_FSTAT, srcFd, a_srcPath, errno, strerror(errno)); 117 (void) close(srcFd); 118 return (1); 119 } 120 121 /* 122 * Determine the permissions mode for the destination: 123 * - if MODE_SET is specified: 124 * --> use a_mode (do not mask off any portion) 125 * --> If a_mode is unknown (? in the pkgmap), then the file gets 126 * --> installed with the default 0644 mode 127 * - if MODE_SRC is specified: 128 * --> use the mode of the source (srcStatbuf.st_mode) but mask off all 129 * --> non-access mode bits (remove SET?UID bits) 130 * - otherwise: 131 * --> use 0666 132 */ 133 134 if (a_ctrl & MODE_SET) { 135 mode_t usemode; 136 137 usemode = (a_mode ^ BADMODE) ? a_mode : 0644; 138 if (a_mode != usemode && usemode == 0644) { 139 logerr(WRN_DEF_MODE, a_dstPath); 140 a_mode = usemode; 141 } 142 } else if (a_ctrl & MODE_SRC) { 143 a_mode = (srcStatbuf.st_mode & S_IAMB); 144 } else { 145 a_mode = 0666; 146 } 147 148 /* 149 * Get fd of newly created destination file or, if this 150 * is an overwrite, a temporary file (linknam). 151 */ 152 153 dstFd = write_file(&linknam, a_ctrl, a_mode, a_dstPath); 154 if (dstFd < 0) { 155 (void) close(srcFd); 156 return (1); 157 } 158 159 /* 160 * source and target files are open: copy data 161 */ 162 163 status = copyFile(srcFd, dstFd, a_srcPath, a_dstPath, &srcStatbuf, 0); 164 165 (void) close(srcFd); 166 (void) close(dstFd); 167 168 if (status != 0) { 169 progerr(ERR_INPUT, a_srcPath, errno, strerror(errno)); 170 if (linknam) { 171 (void) remove(linknam); 172 } 173 return (1); 174 } 175 176 /* 177 * If this is an overwrite, rename temp over original 178 */ 179 180 if ((linknam != (char *)NULL) && (rename(linknam, a_dstPath) != 0)) { 181 FILE *logfp = (FILE *)NULL; 182 char busylog[PATH_MAX]; 183 184 /* output log message if busy else program error */ 185 186 if (errno == ETXTBSY) { 187 logerr(MSG_PROCMV, linknam); 188 } else { 189 progerr(ERR_OUTPUT_WRITING, a_dstPath, errno, 190 strerror(errno)); 191 } 192 193 (void) remove(linknam); 194 195 /* open the log file and append log entry */ 196 197 len = snprintf(busylog, sizeof (busylog), 198 "%s/textbusy", get_PKGADM()); 199 if (len > sizeof (busylog)) { 200 progerr(ERR_CREATE_PATH_2, get_PKGADM(), 201 "textbusy"); 202 } else { 203 logfp = fopen(busylog, "a"); 204 if (logfp == NULL) { 205 progerr(ERR_LOG, busylog, errno, 206 strerror(errno)); 207 } else { 208 (void) fprintf(logfp, "%s\n", linknam); 209 (void) fclose(logfp); 210 } 211 } 212 } 213 214 /* set access/modification times for target */ 215 216 times.actime = srcStatbuf.st_atime; 217 times.modtime = srcStatbuf.st_mtime; 218 219 if (utime(a_dstPath, ×) != 0) { 220 progerr(ERR_MODTIM, a_dstPath, errno, strerror(errno)); 221 return (1); 222 } 223 224 /* success! */ 225 226 return (0); 227 } 228 229 /* 230 * This function creates all of the directory components of the specified path. 231 */ 232 static int 233 create_path(int a_ctrl, char *a_file) 234 { 235 char *pt; 236 int found = 0; 237 238 for (pt = a_file; *pt; pt++) { 239 /* continue if not at path separator or at start of path */ 240 241 if ((*pt != '/') || (pt == a_file)) { 242 continue; 243 } 244 245 /* at '/' - terminate path at current entry */ 246 247 *pt = '\0'; 248 249 /* continue if path element exists */ 250 251 if (access(a_file, F_OK) == 0) { 252 *pt = '/'; 253 continue; 254 } 255 256 /* create directory in path */ 257 258 if (mkdir(a_file, 0755)) { 259 progerr(ERR_MAKE_DIR, a_file, errno, strerror(errno)); 260 *pt = '/'; 261 return (1); 262 } 263 264 /* display 'implied directory created' message */ 265 266 if (a_ctrl & DIR_DISPLAY) { 267 echo(MSG_IMPDIR, a_file); 268 } 269 270 found++; 271 272 *pt = '/'; 273 } 274 275 return (!found); 276 } 277 278 /* 279 * Name: write_file 280 * Description: creates a new destination file if the file does not already 281 * exist; otherwise, creates a temporary file and places a 282 * pointer to the temporary file name in 'r_linknam'. 283 * Arguments: r_linknam - pointer to (char*) where name of temporary file 284 * created is returned 285 * a_ctrl - determine if the destination file name is displayed: 286 * |= DIR_DISPLAY - display "%s <implied directory>" 287 * if directory created 288 * a_mode - permissions mode to set a_file to 289 * a_file - name of destination file to open 290 * Returns: int 291 * success - file descriptor of the file it opened. 292 * failure - returns -1 293 */ 294 295 static int 296 write_file(char **r_linknam, int a_ctrl, mode_t a_mode, char *a_file) 297 { 298 int len; 299 int fd = -1; 300 static char loc_link[PATH_MAX]; 301 302 /* entry debugging */ 303 304 echoDebug(DBG_WRITEFILE_ENTRY, a_ctrl, a_mode, a_file); 305 306 /* reset pointer to returned 'temporary file name' */ 307 308 *r_linknam = (char *)NULL; 309 310 /* 311 * If we are overwriting an existing file, arrange to replace 312 * it transparently. 313 */ 314 315 if (access(a_file, F_OK) == 0) { 316 /* 317 * link the file to be copied to a temporary name in case 318 * it is executing or it is being written/used (e.g., a shell 319 * script currently being executed 320 */ 321 322 if (!RELATIVE(a_file)) { 323 len = snprintf(loc_link, sizeof (loc_link), 324 "%sXXXXXX", a_file); 325 if (len > sizeof (loc_link)) { 326 progerr(ERR_CREATE_PATH_2, a_file, "XXXXXX"); 327 } 328 } else { 329 logerr(WRN_RELATIVE, a_file); 330 len = snprintf(loc_link, sizeof (loc_link), 331 "./%sXXXXXX", a_file); 332 if (len > sizeof (loc_link)) { 333 progerr(ERR_CREATE_PATH_3, "./", a_file, 334 "XXXXXX"); 335 } 336 } 337 338 /* create and open temporary file */ 339 340 fd = mkstemp(loc_link); 341 if (fd == -1) { 342 progerr(ERR_MKTEMP, loc_link, errno, strerror(errno)); 343 return (-1); 344 } 345 346 /* remember name of temporary file */ 347 348 *r_linknam = loc_link; 349 350 /* make sure temporary file has correct mode */ 351 352 if (fchmod(fd, a_mode) < 0) { 353 progerr(ERR_FCHMOD, loc_link, a_mode, errno, 354 strerror(errno)); 355 } 356 357 return (fd); 358 } 359 360 /* 361 * We are not overwriting an existing file, create a new one directly. 362 */ 363 364 fd = open(a_file, O_WRONLY | O_CREAT | O_TRUNC, a_mode); 365 if (fd == -1) { 366 if (create_path(a_ctrl, a_file) == 0) { 367 fd = open(a_file, O_WRONLY | O_CREAT | O_TRUNC, a_mode); 368 } 369 } 370 371 if (fd == -1) { 372 progerr(ERR_OPEN_WRITE, a_file, errno, strerror(errno)); 373 } 374 375 return (fd); 376 } 377