cppath.c revision 9781:ccf49524d5dc
1239310Sdim/*
2239310Sdim * CDDL HEADER START
3353358Sdim *
4353358Sdim * The contents of this file are subject to the terms of the
5353358Sdim * Common Development and Distribution License (the "License").
6239310Sdim * You may not use this file except in compliance with the License.
7239310Sdim *
8239310Sdim * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9239310Sdim * or http://www.opensolaris.org/os/licensing.
10239310Sdim * See the License for the specific language governing permissions
11239310Sdim * and limitations under the License.
12239310Sdim *
13239310Sdim * When distributing Covered Code, include this CDDL HEADER in each
14280031Sdim * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15280031Sdim * If applicable, add the following below this CDDL HEADER, with the
16239310Sdim * fields enclosed by brackets "[]" replaced with your own identifying
17353358Sdim * information: Portions Copyright [yyyy] [name of copyright owner]
18353358Sdim *
19239310Sdim * CDDL HEADER END
20239310Sdim */
21239310Sdim
22239310Sdim/*
23261991Sdim * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24239310Sdim * Use is subject to license terms.
25239310Sdim */
26239310Sdim
27239310Sdim/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28239310Sdim/* All Rights Reserved */
29239310Sdim
30239310Sdim
31239310Sdim/*
32239310Sdim * System includes
33239310Sdim */
34239310Sdim
35239310Sdim#include <stdio.h>
36239310Sdim#include <string.h>
37280031Sdim#include <stdlib.h>
38280031Sdim#include <unistd.h>
39276479Sdim#include <utime.h>
40251662Sdim#include <locale.h>
41309124Sdim#include <libintl.h>
42344779Sdim#include <pkglocs.h>
43261991Sdim#include <errno.h>
44276479Sdim#include <fcntl.h>
45276479Sdim#include <sys/types.h>
46314564Sdim#include <sys/stat.h>
47360784Sdim
48288943Sdim/*
49344779Sdim * consolidation pkg command library includes
50239310Sdim */
51249423Sdim
52239310Sdim#include <pkglib.h>
53239310Sdim
54261991Sdim/*
55239310Sdim * local pkg command library includes
56239310Sdim */
57239310Sdim
58239310Sdim#include "libadm.h"
59239310Sdim#include "libinst.h"
60239310Sdim#include "install.h"
61239310Sdim#include "messages.h"
62239310Sdim#include "pkginstall.h"
63239310Sdim
64239310Sdim/*
65239310Sdim * forward declarations
66239310Sdim */
67239310Sdim
68239310Sdimstatic int	write_file(char **r_linknam, int a_ctrl, mode_t a_mode,
69239310Sdim			char *a_file);
70239310Sdimstatic int	create_path(int a_ctrl, char *a_file);
71239310Sdim
72239310Sdim/*
73239310Sdim * Name:	cppath
74239310Sdim * Description:	copy a path object (install new file on system)
75239310Sdim * Arguments:
76239310Sdim *    - a_cntrl - determine how the destination file mode is set:
77239310Sdim *	|= MODE_0666 - force mode to 0666
78239310Sdim *      |= MODE_SET - mode is a_mode (no mask SET?ID bits)
79239310Sdim *      |= MODE_SRC - mode from source file (mask SET?ID bits)
80239310Sdim *      |= DIR_DISPLAY - display "%s <implied directory>" if directory created
81239310Sdim *    - a_srcPath - path to source to copy
82239310Sdim *    - a_dstPath - path to copy source to
83239310Sdim *    - a_mode - mode to set a_dstpath to (mode controlled by a_ctrl)
84239310Sdim * Returns:	int
85239310Sdim *	== 0 - success
86239310Sdim *	!= 0 - failure
87239310Sdim */
88239310Sdim
89249423Sdimint
90239310Sdimcppath(int a_ctrl, char *a_srcPath, char *a_dstPath, mode_t a_mode)
91239310Sdim{
92239310Sdim	char		*linknam = (char *)NULL;
93239310Sdim	int		dstFd;
94239310Sdim	int		len;
95239310Sdim	int		srcFd;
96239310Sdim	long		status;
97239310Sdim	struct stat	srcStatbuf;
98239310Sdim	struct utimbuf	times;
99239310Sdim
100321369Sdim	/* entry debugging info */
101321369Sdim
102239310Sdim	echoDebug(DBG_CPPATH_ENTRY, a_ctrl, a_mode, a_srcPath, a_dstPath);
103239310Sdim
104239310Sdim	/* open source file for reading */
105239310Sdim
106239310Sdim	srcFd = open(a_srcPath, O_RDONLY);
107239310Sdim	if (srcFd < 0) {
108239310Sdim		progerr(ERR_OPEN_READ, a_srcPath,
109261991Sdim				errno, strerror(errno));
110261991Sdim		return (1);
111261991Sdim	}
112261991Sdim
113261991Sdim	/* obtain file status of source file */
114261991Sdim
115261991Sdim	if (fstat(srcFd, &srcStatbuf) != 0) {
116261991Sdim		progerr(ERR_FSTAT, srcFd, a_srcPath, errno, strerror(errno));
117261991Sdim		(void) close(srcFd);
118261991Sdim		return (1);
119261991Sdim	}
120261991Sdim
121261991Sdim	/*
122261991Sdim	 * Determine the permissions mode for the destination:
123261991Sdim	 * - if MODE_SET is specified:
124261991Sdim	 * --> use a_mode (do not mask off any portion)
125261991Sdim	 * --> If a_mode is unknown (? in the pkgmap), then the file gets
126261991Sdim	 * --> installed with the default 0644 mode
127239310Sdim	 * - if MODE_SRC is specified:
128261991Sdim	 * --> use the mode of the source (srcStatbuf.st_mode) but mask off all
129261991Sdim	 * --> non-access mode bits (remove SET?UID bits)
130261991Sdim	 * - otherwise:
131261991Sdim	 * --> use 0666
132261991Sdim	 */
133261991Sdim
134261991Sdim	if (a_ctrl & MODE_SET) {
135261991Sdim		mode_t	usemode;
136261991Sdim
137261991Sdim		usemode = (a_mode ^ BADMODE) ? a_mode : 0644;
138261991Sdim		if (a_mode != usemode && usemode == 0644) {
139261991Sdim			logerr(WRN_DEF_MODE, a_dstPath);
140261991Sdim			a_mode = usemode;
141261991Sdim		}
142261991Sdim	} else if (a_ctrl & MODE_SRC) {
143261991Sdim		a_mode = (srcStatbuf.st_mode & S_IAMB);
144261991Sdim	} else {
145261991Sdim		a_mode = 0666;
146261991Sdim	}
147261991Sdim
148261991Sdim	/*
149261991Sdim	 * Get fd of newly created destination file or, if this
150261991Sdim	 * is an overwrite,  a temporary file (linknam).
151261991Sdim	 */
152261991Sdim
153261991Sdim	dstFd = write_file(&linknam, a_ctrl, a_mode, a_dstPath);
154261991Sdim	if (dstFd < 0) {
155261991Sdim		(void) close(srcFd);
156261991Sdim		return (1);
157239310Sdim	}
158239310Sdim
159239310Sdim	/*
160239310Sdim	 * source and target files are open: copy data
161239310Sdim	 */
162239310Sdim
163239310Sdim	status = copyFile(srcFd, dstFd, a_srcPath, a_dstPath, &srcStatbuf, 0);
164239310Sdim
165239310Sdim	(void) close(srcFd);
166239310Sdim	(void) close(dstFd);
167239310Sdim
168239310Sdim	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, &times) != 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 */
232static int
233create_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
295static int
296write_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