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