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