8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / tsol / updatehome / setupfiles.c
blob277d12473d33fa5d7676d160cca13198d923e7ff
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <errno.h>
28 #include <pwd.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
38 #include <tsol/label.h>
39 #include <zone.h>
40 #include <sys/stat.h>
42 #include "setupfiles.h"
44 #define dperror(s) if (flags & DIAG) perror(s)
45 #define dprintf(s, v) if (flags & DBUG) (void) printf(s, v)
46 #define dprintf2(s, v1, v2) if (flags & DBUG) (void) printf(s, v1, v2)
48 static int mkdirs(const char *dir, const char *target, int flags);
49 static int copyfile(const char *min_home, const char *home, const char *target,
50 int flags);
51 static int linkfile(const char *min_home, const char *home, const char *target,
52 int flags);
56 * __setupfiles - Process copy and link files directions in min $HOME.
58 * Entry pwd = user's password file entry.
59 * min_sl = user's minimum SL.
60 * flags = DBUG, if print debug messages.
61 * DIAG, if print diagnostics (perrors).
62 * IGNE, continue rather than abort on failures.
63 * REPC, if replace existing file.
64 * REPL, if replace existing symbolic link.
65 * process is running as user at correct label.
67 * Exit None.
69 * Returns 0, if success.
70 * errno, if failure.
72 * Uses COPY, CP, LINK, MAXPATHLEN.
74 * Calls blequal, copyfile, feof, fgets, fopen,
75 * mkdirs, getzoneid, getzonelabelbyid, linkfile, strcat, strcpy,
76 * strlen.
78 * This program assumes the /zone is the autofs mountpoint for
79 * cross-zone mounts.
81 * It also assumes that the user's home directory path is the
82 * the same in each zone, relative to the zone's root.
84 * At this point, the cross-zone automounter only supports home
85 * directories starting with /home
88 int
89 __setupfiles(const struct passwd *pwd, const m_label_t *min_sl, int flags)
91 m_label_t *plabel; /* process label */
92 char home[MAXPATHLEN]; /* real path to current $HOME */
93 char min_home[MAXPATHLEN]; /* real path to min $HOME */
94 char cl_file[MAXPATHLEN]; /* real path to .copy/.link_files */
95 char file[MAXPATHLEN]; /* file to copy/link */
96 FILE *clf; /* .copy/.link_file stream */
97 char zoneroot[MAXPATHLEN];
98 zoneid_t zoneid;
99 zoneid_t min_zoneid;
101 zoneid = getzoneid();
102 if ((plabel = getzonelabelbyid(zoneid)) == NULL) {
104 dperror("setupfiles can't get process label");
105 return (errno);
108 if (blequal(plabel, min_sl)) {
109 /* at min SL no files to setup */
111 return (0);
114 /* get current home real path */
116 (void) strlcpy(home, pwd->pw_dir, MAXPATHLEN);
118 /* Get zone id from min_sl */
120 if ((min_zoneid = getzoneidbylabel(min_sl)) == -1) {
122 dperror("setupfiles can't get zoneid for min sl");
123 return (errno);
127 * Since the global zone home directories aren't public
128 * information, we don't support copy and link files there.
130 if (min_zoneid == GLOBAL_ZONEID)
131 return (0);
134 * Get zone root path from zone id
136 * Could have used getzonenamebyid() but this assumes that /etc/zones
137 * directory is available, which is not true in labeled zones
140 if (zone_getattr(min_zoneid, ZONE_ATTR_ROOT, zoneroot,
141 sizeof (zoneroot)) == -1) {
142 dperror("setupfiles can't get zone root path for min sl");
143 return (errno);
146 (void) snprintf(min_home, MAXPATHLEN, "%s%s",
147 zoneroot, pwd->pw_dir);
149 /* process copy files */
151 if ((strlen(min_home) + strlen(COPY)) > (MAXPATHLEN - 1)) {
153 dprintf("setupfiles copy path %s", min_home);
154 dprintf("%s ", COPY);
155 dprintf("greater than %d\n", MAXPATHLEN);
156 errno = ENAMETOOLONG;
157 dperror("setupfiles copy path");
158 return (errno);
161 (void) strcpy(cl_file, min_home);
162 (void) strcat(cl_file, COPY);
164 if ((clf = fopen(cl_file, "r")) != NULL) {
166 while (fgets(file, MAXPATHLEN, clf) != NULL) {
168 if (!feof(clf)) /* remove trailing \n */
169 file[strlen(file) - 1] = '\0';
171 dprintf("copy file %s requested\n", file);
173 /* make any needed subdirectories */
175 if (mkdirs(home, file, flags) != 0) {
177 if ((flags & IGNE) == 0)
178 return (errno);
179 else
180 continue;
183 /* copy the file */
185 if (copyfile(min_home, home, file, flags) != 0) {
187 if ((flags & IGNE) == 0)
188 return (errno);
189 else
190 continue;
194 } /* while (fgets( ... ) != NULL) */
195 } else {
196 if (errno != ENOENT)
197 dperror("setupfiles copy file open");
198 dprintf("setupfiles no copyfile %s\n", cl_file);
199 } /* process copy files */
202 /* process link files */
204 if ((strlen(min_home) + strlen(LINK)) > (MAXPATHLEN - 1)) {
206 dprintf("setupfiles link path %s", min_home);
207 dprintf("%s ", LINK);
208 dprintf("greater than %d\n", MAXPATHLEN);
209 errno = ENAMETOOLONG;
210 dperror("setupfiles link path");
211 return (errno);
214 (void) strcpy(cl_file, min_home);
215 (void) strcat(cl_file, LINK);
217 if ((clf = fopen(cl_file, "r")) != NULL) {
219 while (fgets(file, MAXPATHLEN, clf) != NULL) {
221 if (!feof(clf)) /* remove trailing \n */
222 file[strlen(file) - 1] = '\0';
224 dprintf("link file %s requested\n", file);
226 /* make any needed subdirectories */
228 if (mkdirs(home, file, flags) != 0) {
230 if ((flags & IGNE) == 0)
231 return (errno);
232 else
233 continue;
236 /* link the file */
238 if (linkfile(min_home, home, file, flags) != 0) {
240 if ((flags & IGNE) == 0)
241 return (errno);
242 else
243 continue;
246 } /* while (fgets ... ) != NULL) */
247 } else {
248 if (errno != ENOENT)
249 dperror("setupfiles link file open");
250 dprintf("setupfiles no linkfile %s\n", cl_file);
251 } /* process link files */
253 return (0);
254 } /* setupfiles() */
258 * mkdirs - Make any needed subdirectories in target's path.
260 * Entry home = base directory.
261 * file = file to create with intermediate subdirectories.
262 * flags = from __setupfiles -- for dprintf and dperror.
264 * Exit Needed subdirectories made.
266 * Returns 0, if success.
267 * errno, if failure.
269 * Uses MAXPATHLEN.
271 * Calls mkdir, strcat, strcpy, strlen, strtok.
274 static int
275 mkdirs(const char *home, const char *file, int flags)
277 char path[MAXPATHLEN];
278 char dir[MAXPATHLEN];
279 char *tok;
281 if ((strlen(home) + strlen(file)) > (MAXPATHLEN - 2)) {
283 dprintf("setupfiles mkdirs path %s", home);
284 dprintf("/%s ", file);
285 dprintf("greater than %d\n", MAXPATHLEN);
286 errno = ENAMETOOLONG;
287 dperror("setupfiles mkdirs");
288 return (errno);
291 (void) strcpy(dir, file);
293 if ((tok = strrchr(dir, '/')) == NULL) {
295 dprintf("setupfiles no dirs to make in %s\n", dir);
296 return (0);
299 *tok = '\000'; /* drop last component, it's the target */
301 (void) strcpy(path, home);
303 for (tok = dir; tok = strtok(tok, "/"); tok = NULL) {
305 (void) strcat(path, "/");
306 (void) strcat(path, tok);
308 if ((mkdir(path, 0777) != 0) && (errno != EEXIST)) {
310 dperror("setupfiles mkdir");
311 dprintf("setupfiles mkdir path %s\n", path);
312 return (errno);
315 dprintf("setupfiles dir %s made or already exists\n", path);
318 return (0);
319 } /* mkdirs() */
323 * copyfile - Copy a file from the base home directory to the current.
325 * Entry min_home = from home directory.
326 * home = current (to) home directory.
327 * target = file to copy.
328 * flags = from __setupfiles.
329 * REPC, if replace existing file.
331 * Exit File copied.
333 * Returns 0, if success.
334 * errno, if failure.
336 * Uses CP, MAXPATHLEN.
338 * Calls access, execlp, exit, lstat, strcat, strcpy, strlen, unlink,
339 * vfork, waitpid.
342 static int
343 copyfile(const char *min_home, const char *home, const char *target, int flags)
345 char src[MAXPATHLEN];
346 char dest[MAXPATHLEN];
347 struct stat buf;
348 pid_t child;
350 /* prepare target */
352 if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
353 sizeof (dest) - 1) {
354 dprintf("setupfiles copy dest %s", dest);
355 dprintf("greater than %d\n", sizeof (dest));
356 errno = ENAMETOOLONG;
357 dperror("setupfiles copy to home");
358 return (errno);
361 if (lstat(dest, &buf) == 0) {
362 /* target exists */
364 if (flags & REPC) {
365 /* unlink and replace */
367 if (unlink(dest) != 0) {
369 dperror("setupfiles copy unlink");
370 dprintf("setupfiles copy unable to unlink %s\n",
371 dest);
372 return (errno);
374 } else {
375 /* target exists and is not to be replaced */
377 return (0);
379 } else if (errno != ENOENT) {
380 /* error on target */
382 dperror("setupfiles copy");
383 dprintf("setupfiles copy lstat %s\n", dest);
384 return (errno);
387 /* prepare source */
389 if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
390 sizeof (src) - 1) {
391 dprintf("setupfiles copy path %s", src);
392 dprintf("greater than %d\n", sizeof (src));
393 errno = ENAMETOOLONG;
394 dperror("setupfiles copy from home");
395 return (errno);
398 if (access(src, R_OK) != 0) {
399 /* can't access source */
401 dperror("setupfiles copy source access");
402 dprintf("setupfiles copy unable to access %s\n", src);
403 return (errno);
406 /* attempt the copy */
408 dprintf("setupfiles attempting to copy %s\n", src);
409 dprintf("\tto %s\n", dest);
411 if ((child = vfork()) != 0) { /* parent, wait for child status */
412 int status; /* child status */
414 (void) waitpid(child, &status, 0); /* wait for child */
415 dprintf("setupfiles copy child returned %x\n", status);
416 } else {
417 /* execute "cp -p min_home home" */
419 if (execlp(CP, CP, "-p", src, dest, 0) != 0) {
420 /* can't execute cp */
422 dperror("setupfiles copy exec");
423 dprintf("setupfiles copy couldn't exec \"%s -p\"\n",
424 CP);
425 exit(2);
429 return (0);
430 } /* copyfile() */
434 * linkfile - Make a symlink from the the current directory to the base
435 * home directory.
437 * Entry min_home = from home directory.
438 * home = current (to) home directory.
439 * target = file to copy.
440 * flags = from __setupfiles.
441 * REPL, if replace existing symlink.
443 * Exit File symlinked.
445 * Returns 0, if success.
446 * errno, if failure.
448 * Uses MAXPATHLEN.
450 * Calls lstat, symlink, strcat, strcpy, strlen, unlink.
453 static int
454 linkfile(const char *min_home, const char *home, const char *target, int flags)
456 char src[MAXPATHLEN];
457 char dest[MAXPATHLEN];
458 struct stat buf;
460 /* prepare target */
462 if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
463 sizeof (dest) - 1) {
464 dprintf("setupfiles link dest %s", dest);
465 dprintf("greater than %d\n", sizeof (dest));
466 errno = ENAMETOOLONG;
467 dperror("setupfiles link to home");
468 return (errno);
471 if (lstat(dest, &buf) == 0) {
472 /* target exists */
474 if (flags & REPL) {
475 /* unlink and replace */
476 if (unlink(dest) != 0) {
477 dperror("setupfiles link unlink");
478 dprintf("setupfiles link unable to unlink %s\n",
479 dest);
480 return (errno);
482 } else {
483 /* target exists and is not to be replaced */
484 return (0);
486 } else if (errno != ENOENT) {
487 /* error on target */
488 dperror("setupfiles link");
489 dprintf("setupfiles link lstat %s\n", dest);
490 return (errno);
493 if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
494 sizeof (src) - 1) {
495 dprintf("setupfiles link path %s", src);
496 dprintf("greater than %d\n", sizeof (src));
497 errno = ENAMETOOLONG;
498 dperror("setupfiles link from home");
499 return (errno);
502 /* attempt the copy */
504 dprintf("setupfiles attempting to link %s\n", dest);
505 dprintf("\tto %s\n", src);
507 if (symlink(src, dest) != 0) {
508 dperror("setupfiles link symlink");
509 dprintf("setupfiles link unable to symlink%s\n", "");
510 return (errno);
513 return (0);
514 } /* linkfile */