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
cppath(int a_ctrl,char * a_srcPath,char * a_dstPath,mode_t a_mode)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
create_path(int a_ctrl,char * a_file)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
write_file(char ** r_linknam,int a_ctrl,mode_t a_mode,char * a_file)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