1f875b4ebSrica /*
2f875b4ebSrica  * CDDL HEADER START
3f875b4ebSrica  *
4f875b4ebSrica  * The contents of this file are subject to the terms of the
5f875b4ebSrica  * Common Development and Distribution License (the "License").
6f875b4ebSrica  * You may not use this file except in compliance with the License.
7f875b4ebSrica  *
8f875b4ebSrica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f875b4ebSrica  * or http://www.opensolaris.org/os/licensing.
10f875b4ebSrica  * See the License for the specific language governing permissions
11f875b4ebSrica  * and limitations under the License.
12f875b4ebSrica  *
13f875b4ebSrica  * When distributing Covered Code, include this CDDL HEADER in each
14f875b4ebSrica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f875b4ebSrica  * If applicable, add the following below this CDDL HEADER, with the
16f875b4ebSrica  * fields enclosed by brackets "[]" replaced with your own identifying
17f875b4ebSrica  * information: Portions Copyright [yyyy] [name of copyright owner]
18f875b4ebSrica  *
19f875b4ebSrica  * CDDL HEADER END
20f875b4ebSrica  */
21f875b4ebSrica 
22f875b4ebSrica /*
23*7b0bedd4SRic Aleshire  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24f875b4ebSrica  * Use is subject to license terms.
25f875b4ebSrica  */
26f875b4ebSrica 
27f875b4ebSrica #include <errno.h>
28f875b4ebSrica #include <pwd.h>
29f875b4ebSrica #include <stdio.h>
30f875b4ebSrica #include <stdlib.h>
31f875b4ebSrica #include <string.h>
32f875b4ebSrica #include <unistd.h>
33f875b4ebSrica 
34f875b4ebSrica #include <sys/param.h>
35f875b4ebSrica #include <sys/types.h>
36f875b4ebSrica #include <sys/wait.h>
37f875b4ebSrica 
38f875b4ebSrica #include <tsol/label.h>
39f875b4ebSrica #include <zone.h>
40f875b4ebSrica #include <sys/stat.h>
41f875b4ebSrica 
42f875b4ebSrica #include "setupfiles.h"
43f875b4ebSrica 
44f875b4ebSrica #define	dperror(s) if (flags & DIAG) perror(s)
45f875b4ebSrica #define	dprintf(s, v) if (flags & DBUG) (void) printf(s, v)
46f875b4ebSrica #define	dprintf2(s, v1, v2) if (flags & DBUG) (void) printf(s, v1, v2)
47f875b4ebSrica 
48f875b4ebSrica static int mkdirs(const char *dir, const char *target, int flags);
49f875b4ebSrica static int copyfile(const char *min_home, const char *home, const char *target,
50f875b4ebSrica     int flags);
51f875b4ebSrica static int linkfile(const char *min_home, const char *home, const char *target,
52f875b4ebSrica     int flags);
53f875b4ebSrica 
54f875b4ebSrica 
55f875b4ebSrica /*
56f875b4ebSrica  *	__setupfiles - Process copy and link files directions in min $HOME.
57f875b4ebSrica  *
58f875b4ebSrica  *	Entry	pwd = user's password file entry.
59f875b4ebSrica  *		min_sl = user's minimum SL.
60f875b4ebSrica  *		flags = DBUG, if print debug messages.
61f875b4ebSrica  *			DIAG, if print diagnostics (perrors).
62f875b4ebSrica  *			IGNE, continue rather than abort on failures.
63f875b4ebSrica  *			REPC, if replace existing file.
64f875b4ebSrica  *			REPL, if replace existing symbolic link.
65f875b4ebSrica  *		process is running as user at correct label.
66f875b4ebSrica  *
67f875b4ebSrica  *	Exit	None.
68f875b4ebSrica  *
69f875b4ebSrica  *	Returns	0, if success.
70f875b4ebSrica  *		errno, if failure.
71f875b4ebSrica  *
72f875b4ebSrica  *	Uses	COPY, CP, LINK, MAXPATHLEN.
73f875b4ebSrica  *
74*7b0bedd4SRic Aleshire  *	Calls	blequal, copyfile, feof, fgets, fopen,
75f875b4ebSrica  *		mkdirs, getzoneid, getzonelabelbyid, linkfile, strcat, strcpy,
76f875b4ebSrica  *		strlen.
77f875b4ebSrica  *
78f875b4ebSrica  *	This program assumes the /zone is the autofs mountpoint for
79f875b4ebSrica  *	cross-zone mounts.
80f875b4ebSrica  *
81f875b4ebSrica  *	It also assumes that the user's home directory path is the
82f875b4ebSrica  *	the same in each zone, relative to the zone's root.
83f875b4ebSrica  *
84f875b4ebSrica  *	At this point, the cross-zone automounter only supports home
85f875b4ebSrica  * 	directories starting with /home
86f875b4ebSrica  */
87f875b4ebSrica 
88f875b4ebSrica int
__setupfiles(const struct passwd * pwd,const m_label_t * min_sl,int flags)89*7b0bedd4SRic Aleshire __setupfiles(const struct passwd *pwd, const m_label_t *min_sl, int flags)
90f875b4ebSrica {
91*7b0bedd4SRic Aleshire 	m_label_t *plabel;		/* process label */
92f875b4ebSrica 	char	home[MAXPATHLEN];	/* real path to current $HOME */
93f875b4ebSrica 	char	min_home[MAXPATHLEN];	/* real path to min $HOME */
94f875b4ebSrica 	char	cl_file[MAXPATHLEN];	/* real path to .copy/.link_files */
95f875b4ebSrica 	char	file[MAXPATHLEN];	/* file to copy/link */
96f875b4ebSrica 	FILE	*clf;			/* .copy/.link_file stream */
97f875b4ebSrica 	char	zoneroot[MAXPATHLEN];
98f875b4ebSrica 	zoneid_t zoneid;
99f875b4ebSrica 	zoneid_t min_zoneid;
100f875b4ebSrica 
101f875b4ebSrica 	zoneid = getzoneid();
102f875b4ebSrica 	if ((plabel = getzonelabelbyid(zoneid)) == NULL) {
103f875b4ebSrica 
104f875b4ebSrica 		dperror("setupfiles can't get process label");
105f875b4ebSrica 		return (errno);
106f875b4ebSrica 	}
107f875b4ebSrica 
108f875b4ebSrica 	if (blequal(plabel, min_sl)) {
109f875b4ebSrica 		/* at min SL no files to setup */
110f875b4ebSrica 
111f875b4ebSrica 		return (0);
112f875b4ebSrica 	}
113f875b4ebSrica 
114f875b4ebSrica 	/* get current home real path */
115f875b4ebSrica 
116f875b4ebSrica 	(void) strlcpy(home, pwd->pw_dir, MAXPATHLEN);
117f875b4ebSrica 
118f875b4ebSrica 	/* Get zone id from min_sl */
119f875b4ebSrica 
120f875b4ebSrica 	if ((min_zoneid = getzoneidbylabel(min_sl)) == -1) {
121f875b4ebSrica 
122f875b4ebSrica 		dperror("setupfiles can't get zoneid for min sl");
123f875b4ebSrica 		return (errno);
124f875b4ebSrica 	}
125f875b4ebSrica 
126f875b4ebSrica 	/*
127f875b4ebSrica 	 * Since the global zone home directories aren't public
128f875b4ebSrica 	 * information, we don't support copy and link files there.
129f875b4ebSrica 	 */
130f875b4ebSrica 	if (min_zoneid == GLOBAL_ZONEID)
131f875b4ebSrica 		return (0);
132f875b4ebSrica 
133f875b4ebSrica 	/*
134f875b4ebSrica 	 * Get zone root path from zone id
135f875b4ebSrica 	 *
136f875b4ebSrica 	 * Could have used getzonenamebyid() but this assumes that /etc/zones
137f875b4ebSrica 	 * directory is available, which is not true in labeled zones
138f875b4ebSrica 	 */
139f875b4ebSrica 
140f875b4ebSrica 	if (zone_getattr(min_zoneid, ZONE_ATTR_ROOT, zoneroot,
141f875b4ebSrica 	    sizeof (zoneroot)) == -1) {
142f875b4ebSrica 		dperror("setupfiles can't get zone root path for min sl");
143f875b4ebSrica 		return (errno);
144f875b4ebSrica 	}
145f875b4ebSrica 
146f875b4ebSrica 	(void) snprintf(min_home, MAXPATHLEN, "%s%s",
147f875b4ebSrica 	    zoneroot, pwd->pw_dir);
148f875b4ebSrica 
149f875b4ebSrica 	/* process copy files */
150f875b4ebSrica 
151f875b4ebSrica 	if ((strlen(min_home) + strlen(COPY)) > (MAXPATHLEN - 1)) {
152f875b4ebSrica 
153f875b4ebSrica 		dprintf("setupfiles copy path %s", min_home);
154f875b4ebSrica 		dprintf("%s ", COPY);
155f875b4ebSrica 		dprintf("greater than %d\n", MAXPATHLEN);
156f875b4ebSrica 		errno = ENAMETOOLONG;
157f875b4ebSrica 		dperror("setupfiles copy path");
158f875b4ebSrica 		return (errno);
159f875b4ebSrica 	}
160f875b4ebSrica 
161f875b4ebSrica 	(void) strcpy(cl_file, min_home);
162f875b4ebSrica 	(void) strcat(cl_file, COPY);
163f875b4ebSrica 
164f875b4ebSrica 	if ((clf = fopen(cl_file, "r")) != NULL) {
165f875b4ebSrica 
166f875b4ebSrica 		while (fgets(file, MAXPATHLEN, clf) != NULL) {
167f875b4ebSrica 
168f875b4ebSrica 			if (!feof(clf))		/* remove trailing \n */
169f875b4ebSrica 				file[strlen(file) - 1] = '\0';
170f875b4ebSrica 
171f875b4ebSrica 			dprintf("copy file %s requested\n", file);
172f875b4ebSrica 
173f875b4ebSrica 			/* make any needed subdirectories */
174f875b4ebSrica 
175f875b4ebSrica 			if (mkdirs(home, file, flags) != 0) {
176f875b4ebSrica 
177f875b4ebSrica 				if ((flags & IGNE) == 0)
178f875b4ebSrica 					return (errno);
179f875b4ebSrica 				else
180f875b4ebSrica 					continue;
181f875b4ebSrica 			}
182f875b4ebSrica 
183f875b4ebSrica 			/* copy the file */
184f875b4ebSrica 
185f875b4ebSrica 			if (copyfile(min_home, home, file, flags) != 0) {
186f875b4ebSrica 
187f875b4ebSrica 				if ((flags & IGNE) == 0)
188f875b4ebSrica 					return (errno);
189f875b4ebSrica 				else
190f875b4ebSrica 					continue;
191f875b4ebSrica 
192f875b4ebSrica 			}
193f875b4ebSrica 
194f875b4ebSrica 		}  /* while (fgets( ... ) != NULL) */
195f875b4ebSrica 	} else {
196f875b4ebSrica 		if (errno != ENOENT)
197f875b4ebSrica 			dperror("setupfiles copy file open");
198f875b4ebSrica 		dprintf("setupfiles no copyfile %s\n", cl_file);
199f875b4ebSrica 	}  /* process copy files */
200f875b4ebSrica 
201f875b4ebSrica 
202f875b4ebSrica 	/* process link files */
203f875b4ebSrica 
204f875b4ebSrica 	if ((strlen(min_home) + strlen(LINK)) > (MAXPATHLEN - 1)) {
205f875b4ebSrica 
206f875b4ebSrica 		dprintf("setupfiles link path %s", min_home);
207f875b4ebSrica 		dprintf("%s ", LINK);
208f875b4ebSrica 		dprintf("greater than %d\n", MAXPATHLEN);
209f875b4ebSrica 		errno = ENAMETOOLONG;
210f875b4ebSrica 		dperror("setupfiles link path");
211f875b4ebSrica 		return (errno);
212f875b4ebSrica 	}
213f875b4ebSrica 
214f875b4ebSrica 	(void) strcpy(cl_file, min_home);
215f875b4ebSrica 	(void) strcat(cl_file, LINK);
216f875b4ebSrica 
217f875b4ebSrica 	if ((clf = fopen(cl_file, "r")) != NULL) {
218f875b4ebSrica 
219f875b4ebSrica 		while (fgets(file, MAXPATHLEN, clf) != NULL) {
220f875b4ebSrica 
221f875b4ebSrica 			if (!feof(clf))		/* remove trailing \n */
222f875b4ebSrica 				file[strlen(file) - 1] = '\0';
223f875b4ebSrica 
224f875b4ebSrica 			dprintf("link file %s requested\n", file);
225f875b4ebSrica 
226f875b4ebSrica 			/* make any needed subdirectories */
227f875b4ebSrica 
228f875b4ebSrica 			if (mkdirs(home, file, flags) != 0) {
229f875b4ebSrica 
230f875b4ebSrica 				if ((flags & IGNE) == 0)
231f875b4ebSrica 					return (errno);
232f875b4ebSrica 				else
233f875b4ebSrica 					continue;
234f875b4ebSrica 			}
235f875b4ebSrica 
236f875b4ebSrica 			/* link the file */
237f875b4ebSrica 
238f875b4ebSrica 			if (linkfile(min_home, home, file, flags) != 0) {
239f875b4ebSrica 
240f875b4ebSrica 				if ((flags & IGNE) == 0)
241f875b4ebSrica 					return (errno);
242f875b4ebSrica 				else
243f875b4ebSrica 					continue;
244f875b4ebSrica 			}
245f875b4ebSrica 
246f875b4ebSrica 		}  /* while (fgets ... ) != NULL) */
247f875b4ebSrica 	} else {
248f875b4ebSrica 		if (errno != ENOENT)
249f875b4ebSrica 			dperror("setupfiles link file open");
250f875b4ebSrica 		dprintf("setupfiles no linkfile %s\n", cl_file);
251f875b4ebSrica 	}  /* process link files */
252f875b4ebSrica 
253f875b4ebSrica 	return (0);
254f875b4ebSrica }  /* setupfiles() */
255f875b4ebSrica 
256f875b4ebSrica 
257f875b4ebSrica /*
258f875b4ebSrica  *	mkdirs - Make any needed subdirectories in target's path.
259f875b4ebSrica  *
260f875b4ebSrica  *	Entry	home = base directory.
261f875b4ebSrica  *		file = file to create with intermediate subdirectories.
262f875b4ebSrica  *		flags = from __setupfiles -- for dprintf and dperror.
263f875b4ebSrica  *
264f875b4ebSrica  *	Exit	Needed subdirectories made.
265f875b4ebSrica  *
266f875b4ebSrica  *	Returns	0, if success.
267f875b4ebSrica  *		errno, if failure.
268f875b4ebSrica  *
269f875b4ebSrica  *	Uses	MAXPATHLEN.
270f875b4ebSrica  *
271f875b4ebSrica  *	Calls	mkdir, strcat, strcpy, strlen, strtok.
272f875b4ebSrica  */
273f875b4ebSrica 
274f875b4ebSrica static int
mkdirs(const char * home,const char * file,int flags)275f875b4ebSrica mkdirs(const char *home, const char *file, int flags)
276f875b4ebSrica {
277f875b4ebSrica 	char	path[MAXPATHLEN];
278f875b4ebSrica 	char	dir[MAXPATHLEN];
279f875b4ebSrica 	char	*tok;
280f875b4ebSrica 
281f875b4ebSrica 	if ((strlen(home) + strlen(file)) > (MAXPATHLEN - 2)) {
282f875b4ebSrica 
283f875b4ebSrica 		dprintf("setupfiles mkdirs path %s", home);
284f875b4ebSrica 		dprintf("/%s ", file);
285f875b4ebSrica 		dprintf("greater than %d\n", MAXPATHLEN);
286f875b4ebSrica 		errno = ENAMETOOLONG;
287f875b4ebSrica 		dperror("setupfiles mkdirs");
288f875b4ebSrica 		return (errno);
289f875b4ebSrica 	}
290f875b4ebSrica 
291f875b4ebSrica 	(void) strcpy(dir, file);
292f875b4ebSrica 
293f875b4ebSrica 	if ((tok = strrchr(dir, '/')) == NULL) {
294f875b4ebSrica 
295f875b4ebSrica 		dprintf("setupfiles no dirs to make in %s\n", dir);
296f875b4ebSrica 		return (0);
297f875b4ebSrica 	}
298f875b4ebSrica 
299f875b4ebSrica 	*tok = '\000';		/* drop last component, it's the target */
300f875b4ebSrica 
301f875b4ebSrica 	(void) strcpy(path, home);
302f875b4ebSrica 
303f875b4ebSrica 	for (tok = dir; tok = strtok(tok, "/"); tok = NULL) {
304f875b4ebSrica 
305f875b4ebSrica 		(void) strcat(path, "/");
306f875b4ebSrica 		(void) strcat(path, tok);
307f875b4ebSrica 
308f875b4ebSrica 		if ((mkdir(path, 0777) != 0) && (errno != EEXIST)) {
309f875b4ebSrica 
310f875b4ebSrica 			dperror("setupfiles mkdir");
311f875b4ebSrica 			dprintf("setupfiles mkdir path %s\n", path);
312f875b4ebSrica 			return (errno);
313f875b4ebSrica 		}
314f875b4ebSrica 
315f875b4ebSrica 		dprintf("setupfiles dir %s made or already exists\n", path);
316f875b4ebSrica 	}
317f875b4ebSrica 
318f875b4ebSrica 	return (0);
319f875b4ebSrica }  /* mkdirs() */
320f875b4ebSrica 
321f875b4ebSrica 
322f875b4ebSrica /*
323f875b4ebSrica  *	copyfile - Copy a file from the base home directory to the current.
324f875b4ebSrica  *
325f875b4ebSrica  *	Entry	min_home = from home directory.
326f875b4ebSrica  *		home = current (to) home directory.
327f875b4ebSrica  *		target = file to copy.
328f875b4ebSrica  *		flags = from __setupfiles.
329f875b4ebSrica  *			REPC, if replace existing file.
330f875b4ebSrica  *
331f875b4ebSrica  *	Exit	File copied.
332f875b4ebSrica  *
333f875b4ebSrica  *	Returns	0, if success.
334f875b4ebSrica  *		errno, if failure.
335f875b4ebSrica  *
336f875b4ebSrica  *	Uses	CP, MAXPATHLEN.
337f875b4ebSrica  *
338f875b4ebSrica  *	Calls	access, execlp, exit, lstat, strcat, strcpy, strlen, unlink,
339f875b4ebSrica  *		vfork, waitpid.
340f875b4ebSrica  */
341f875b4ebSrica 
342f875b4ebSrica static int
copyfile(const char * min_home,const char * home,const char * target,int flags)343f875b4ebSrica copyfile(const char *min_home, const char *home, const char *target, int flags)
344f875b4ebSrica {
345f875b4ebSrica 	char	src[MAXPATHLEN];
346f875b4ebSrica 	char	dest[MAXPATHLEN];
347f875b4ebSrica 	struct stat	buf;
348f875b4ebSrica 	pid_t	child;
349f875b4ebSrica 
350f875b4ebSrica 	/* prepare target */
351f875b4ebSrica 
352f875b4ebSrica 	if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
353f875b4ebSrica 	    sizeof (dest) - 1) {
354f875b4ebSrica 		dprintf("setupfiles copy dest %s", dest);
355f875b4ebSrica 		dprintf("greater than %d\n", sizeof (dest));
356f875b4ebSrica 		errno = ENAMETOOLONG;
357f875b4ebSrica 		dperror("setupfiles copy to home");
358f875b4ebSrica 		return (errno);
359f875b4ebSrica 	}
360f875b4ebSrica 
361f875b4ebSrica 	if (lstat(dest, &buf) == 0) {
362f875b4ebSrica 		/* target exists */
363f875b4ebSrica 
364f875b4ebSrica 		if (flags & REPC) {
365f875b4ebSrica 			/* unlink and replace */
366f875b4ebSrica 
367f875b4ebSrica 			if (unlink(dest) != 0) {
368f875b4ebSrica 
369f875b4ebSrica 				dperror("setupfiles copy unlink");
370f875b4ebSrica 				dprintf("setupfiles copy unable to unlink %s\n",
371f875b4ebSrica 				    dest);
372f875b4ebSrica 				return (errno);
373f875b4ebSrica 			}
374f875b4ebSrica 		} else {
375f875b4ebSrica 			/* target exists and is not to be replaced */
376f875b4ebSrica 
377f875b4ebSrica 			return (0);
378f875b4ebSrica 		}
379f875b4ebSrica 	} else if (errno != ENOENT) {
380f875b4ebSrica 		/* error on target */
381f875b4ebSrica 
382f875b4ebSrica 		dperror("setupfiles copy");
383f875b4ebSrica 		dprintf("setupfiles copy lstat %s\n", dest);
384f875b4ebSrica 		return (errno);
385f875b4ebSrica 	}
386f875b4ebSrica 
387f875b4ebSrica 	/* prepare source */
388f875b4ebSrica 
389f875b4ebSrica 	if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
390f875b4ebSrica 	    sizeof (src) - 1) {
391f875b4ebSrica 		dprintf("setupfiles copy path %s", src);
392f875b4ebSrica 		dprintf("greater than %d\n", sizeof (src));
393f875b4ebSrica 		errno = ENAMETOOLONG;
394f875b4ebSrica 		dperror("setupfiles copy from home");
395f875b4ebSrica 		return (errno);
396f875b4ebSrica 	}
397f875b4ebSrica 
398f875b4ebSrica 	if (access(src, R_OK) != 0) {
399f875b4ebSrica 		/* can't access source */
400f875b4ebSrica 
401f875b4ebSrica 		dperror("setupfiles copy source access");
402f875b4ebSrica 		dprintf("setupfiles copy unable to access %s\n", src);
403f875b4ebSrica 		return (errno);
404f875b4ebSrica 	}
405f875b4ebSrica 
406f875b4ebSrica 	/* attempt the copy */
407f875b4ebSrica 
408f875b4ebSrica 	dprintf("setupfiles attempting to copy %s\n", src);
409f875b4ebSrica 	dprintf("\tto %s\n", dest);
410f875b4ebSrica 
411f875b4ebSrica 	if ((child = vfork()) != 0) {	/* parent, wait for child status */
412f875b4ebSrica 		int	status;	/* child status */
413f875b4ebSrica 
414f875b4ebSrica 		(void) waitpid(child, &status, 0);  /* wait for child */
415f875b4ebSrica 		dprintf("setupfiles copy child returned %x\n", status);
416f875b4ebSrica 	} else {
417f875b4ebSrica 		/* execute "cp -p min_home home" */
418f875b4ebSrica 
419f875b4ebSrica 		if (execlp(CP, CP, "-p", src, dest, 0) != 0) {
420f875b4ebSrica 			/* can't execute cp */
421f875b4ebSrica 
422f875b4ebSrica 			dperror("setupfiles copy exec");
423f875b4ebSrica 			dprintf("setupfiles copy couldn't exec \"%s  -p\"\n",
424f875b4ebSrica 			    CP);
425f875b4ebSrica 			exit(2);
426f875b4ebSrica 		}
427f875b4ebSrica 	}
428f875b4ebSrica 
429f875b4ebSrica 	return (0);
430f875b4ebSrica }  /* copyfile() */
431f875b4ebSrica 
432f875b4ebSrica 
433f875b4ebSrica /*
434f875b4ebSrica  *	linkfile - Make a symlink from the the current directory to the base
435f875b4ebSrica  *			home directory.
436f875b4ebSrica  *
437f875b4ebSrica  *	Entry	min_home = from home directory.
438f875b4ebSrica  *		home = current (to) home directory.
439f875b4ebSrica  *		target = file to copy.
440f875b4ebSrica  *		flags = from __setupfiles.
441f875b4ebSrica  *			REPL, if replace existing symlink.
442f875b4ebSrica  *
443f875b4ebSrica  *	Exit	File symlinked.
444f875b4ebSrica  *
445f875b4ebSrica  *	Returns	0, if success.
446f875b4ebSrica  *		errno, if failure.
447f875b4ebSrica  *
448f875b4ebSrica  *	Uses	MAXPATHLEN.
449f875b4ebSrica  *
450f875b4ebSrica  *	Calls	lstat, symlink, strcat, strcpy, strlen, unlink.
451f875b4ebSrica  */
452f875b4ebSrica 
453f875b4ebSrica static int
linkfile(const char * min_home,const char * home,const char * target,int flags)454f875b4ebSrica linkfile(const char *min_home, const char *home, const char *target, int flags)
455f875b4ebSrica {
456f875b4ebSrica 	char	src[MAXPATHLEN];
457f875b4ebSrica 	char	dest[MAXPATHLEN];
458f875b4ebSrica 	struct stat	buf;
459f875b4ebSrica 
460f875b4ebSrica 	/* prepare target */
461f875b4ebSrica 
462f875b4ebSrica 	if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
463f875b4ebSrica 	    sizeof (dest) - 1) {
464f875b4ebSrica 		dprintf("setupfiles link dest %s", dest);
465f875b4ebSrica 		dprintf("greater than %d\n", sizeof (dest));
466f875b4ebSrica 		errno = ENAMETOOLONG;
467f875b4ebSrica 		dperror("setupfiles link to home");
468f875b4ebSrica 		return (errno);
469f875b4ebSrica 	}
470f875b4ebSrica 
471f875b4ebSrica 	if (lstat(dest, &buf) == 0) {
472f875b4ebSrica 		/* target exists */
473f875b4ebSrica 
474f875b4ebSrica 		if (flags & REPL) {
475f875b4ebSrica 			/* unlink and replace */
476f875b4ebSrica 			if (unlink(dest) != 0) {
477f875b4ebSrica 				dperror("setupfiles link unlink");
478f875b4ebSrica 				dprintf("setupfiles link unable to unlink %s\n",
479f875b4ebSrica 				    dest);
480f875b4ebSrica 				return (errno);
481f875b4ebSrica 			}
482f875b4ebSrica 		} else {
483f875b4ebSrica 			/* target exists and is not to be replaced */
484f875b4ebSrica 			return (0);
485f875b4ebSrica 		}
486f875b4ebSrica 	} else if (errno != ENOENT) {
487f875b4ebSrica 		/* error on target */
488f875b4ebSrica 		dperror("setupfiles link");
489f875b4ebSrica 		dprintf("setupfiles link lstat %s\n", dest);
490f875b4ebSrica 		return (errno);
491f875b4ebSrica 	}
492f875b4ebSrica 
493f875b4ebSrica 	if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
494f875b4ebSrica 	    sizeof (src) - 1) {
495f875b4ebSrica 		dprintf("setupfiles link path %s", src);
496f875b4ebSrica 		dprintf("greater than %d\n", sizeof (src));
497f875b4ebSrica 		errno = ENAMETOOLONG;
498f875b4ebSrica 		dperror("setupfiles link from home");
499f875b4ebSrica 		return (errno);
500f875b4ebSrica 	}
501f875b4ebSrica 
502f875b4ebSrica 	/* attempt the copy */
503f875b4ebSrica 
504f875b4ebSrica 	dprintf("setupfiles attempting to link %s\n", dest);
505f875b4ebSrica 	dprintf("\tto %s\n", src);
506f875b4ebSrica 
507f875b4ebSrica 	if (symlink(src, dest) != 0) {
508f875b4ebSrica 		dperror("setupfiles link symlink");
509f875b4ebSrica 		dprintf("setupfiles link unable to symlink%s\n", "");
510f875b4ebSrica 		return (errno);
511f875b4ebSrica 	}
512f875b4ebSrica 
513f875b4ebSrica 	return (0);
514f875b4ebSrica }  /* linkfile */
515