8723 autofs: cstyle fixes after 8717
[unleashed.git] / usr / src / cmd / fs.d / autofs / ns_files.c
blob9507fc0fc78cd842eceb9f7eb236d642d2ba9983
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
22 * ns_files.c
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <syslog.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <nsswitch.h>
34 #include <sys/stat.h>
35 #include <sys/param.h>
36 #include <rpc/rpc.h>
37 #include <rpcsvc/nfs_prot.h>
38 #include <thread.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <synch.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <strings.h>
47 #include "automount.h"
49 static int read_execout(char *, char **, char *, char *, int);
50 static int call_read_execout(char *, char *, char *, int);
51 static FILE *file_open(char *, char *, char **, char ***);
54 * Initialize the stack
56 void
57 init_files(char **stack, char ***stkptr)
60 * The call is bogus for automountd since the stack is
61 * is more appropriately initialized in the thread-private
62 * routines
64 if (stack == NULL && stkptr == NULL)
65 return;
66 (void) stack_op(INIT, NULL, stack, stkptr);
69 int
70 getmapent_files(char *key, char *mapname, struct mapline *ml,
71 char **stack, char ***stkptr, bool_t *iswildcard, bool_t isrestricted)
73 int nserr;
74 FILE *fp;
75 char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
76 char linebuf[LINESZ], lineqbuf[LINESZ];
77 char *lp, *lq;
78 struct stat stbuf;
79 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
80 int syntaxok = 1;
82 if (iswildcard)
83 *iswildcard = FALSE;
84 if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) {
85 nserr = __NSW_UNAVAIL;
86 goto done;
89 if (stat(fname, &stbuf) < 0) {
90 nserr = __NSW_UNAVAIL;
91 goto done;
95 * If the file has its execute bit on then
96 * assume it's an executable map.
97 * Execute it and pass the key as an argument.
98 * Expect to get a map entry on the stdout.
99 * Ignore the "x" bit on restricted maps.
101 if (!isrestricted && (stbuf.st_mode & S_IXUSR)) {
102 int rc;
104 if (trace > 1) {
105 trace_prt(1, "\tExecutable map: map=%s key=%s\n",
106 fname, key);
109 rc = call_read_execout(key, fname, ml->linebuf, LINESZ);
111 if (rc != 0) {
112 nserr = __NSW_UNAVAIL;
113 goto done;
116 if (strlen(ml->linebuf) == 0) {
117 nserr = __NSW_NOTFOUND;
118 goto done;
121 unquote(ml->linebuf, ml->lineqbuf);
122 nserr = __NSW_SUCCESS;
123 goto done;
128 * It's just a normal map file.
129 * Search for the entry with the required key.
131 for (;;) {
132 lp = get_line(fp, fname, linebuf, sizeof (linebuf));
133 if (lp == NULL) {
134 nserr = __NSW_NOTFOUND;
135 goto done;
137 if (verbose && syntaxok && isspace(*(uchar_t *)lp)) {
138 syntaxok = 0;
139 syslog(LOG_ERR,
140 "leading space in map entry \"%s\" in %s",
141 lp, mapname);
143 lq = lineqbuf;
144 unquote(lp, lq);
145 if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word))
146 == -1) || (word[0] == '\0'))
147 continue;
148 if (strcmp(word, key) == 0)
149 break;
150 if (word[0] == '*' && word[1] == '\0') {
151 if (iswildcard)
152 *iswildcard = TRUE;
153 break;
155 if (word[0] == '+') {
156 nserr = getmapent(key, word+1, ml, stack, stkptr,
157 iswildcard, isrestricted);
158 if (nserr == __NSW_SUCCESS)
159 goto done;
160 continue;
164 * sanity check each map entry key against
165 * the lookup key as the map is searched.
167 if (verbose && syntaxok) { /* sanity check entry */
168 if (*key == '/') {
169 if (*word != '/') {
170 syntaxok = 0;
171 syslog(LOG_ERR, "bad key \"%s\" in "
172 "direct map %s\n", word, mapname);
174 } else {
175 if (strchr(word, '/')) {
176 syntaxok = 0;
177 syslog(LOG_ERR, "bad key \"%s\" in "
178 "indirect map %s\n", word, mapname);
184 (void) strcpy(ml->linebuf, lp);
185 (void) strcpy(ml->lineqbuf, lq);
186 nserr = __NSW_SUCCESS;
187 done:
188 if (fp) {
189 (void) stack_op(POP, (char *)NULL, stack, stkptr);
190 (void) fclose(fp);
194 return (nserr);
198 getmapkeys_files(char *mapname, struct dir_entry **list, int *error,
199 int *cache_time, char **stack, char ***stkptr)
201 FILE *fp = NULL;
202 char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
203 char linebuf[LINESZ], lineqbuf[LINESZ];
204 char *lp, *lq;
205 struct stat stbuf;
206 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
207 int syntaxok = 1;
208 int nserr;
209 struct dir_entry *last = NULL;
211 if (trace > 1)
212 trace_prt(1, "getmapkeys_files %s\n", mapname);
214 *cache_time = RDDIR_CACHE_TIME;
215 if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) {
216 *error = ENOENT;
217 nserr = __NSW_UNAVAIL;
218 goto done;
220 if (fseek(fp, 0L, SEEK_SET) == -1) {
221 *error = ENOENT;
222 nserr = __NSW_UNAVAIL;
223 goto done;
226 if (stat(fname, &stbuf) < 0) {
227 *error = ENOENT;
228 nserr = __NSW_UNAVAIL;
229 goto done;
233 * If the file has its execute bit on then
234 * assume it's an executable map.
235 * I don't know how to list executable maps, return
236 * an empty map.
238 if (stbuf.st_mode & S_IXUSR) {
239 *error = 0;
240 nserr = __NSW_SUCCESS;
241 goto done;
244 * It's just a normal map file.
245 * List entries one line at a time.
247 for (;;) {
248 lp = get_line(fp, fname, linebuf, sizeof (linebuf));
249 if (lp == NULL) {
250 nserr = __NSW_SUCCESS;
251 goto done;
253 if (syntaxok && isspace(*(uchar_t *)lp)) {
254 syntaxok = 0;
255 syslog(LOG_ERR,
256 "leading space in map entry \"%s\" in %s",
257 lp, mapname);
259 lq = lineqbuf;
260 unquote(lp, lq);
261 if ((getword(word, wordq, &lp, &lq, ' ', MAXFILENAMELEN)
262 == -1) || (word[0] == '\0'))
263 continue;
265 * Wildcard entries should be ignored and this should be
266 * the last entry read to corroborate the search through
267 * files, i.e., search for key until a wildcard is reached.
269 if (word[0] == '*' && word[1] == '\0')
270 break;
271 if (word[0] == '+') {
273 * Name switch here
275 getmapkeys(word+1, list, error, cache_time,
276 stack, stkptr, 0);
278 * the list may have been updated, therefore
279 * our 'last' may no longer be valid
281 last = NULL;
282 continue;
285 if (add_dir_entry(word, list, &last) != 0) {
286 *error = ENOMEM;
287 goto done;
289 assert(last != NULL);
292 nserr = __NSW_SUCCESS;
293 done:
294 if (fp) {
295 (void) stack_op(POP, (char *)NULL, stack, stkptr);
296 (void) fclose(fp);
299 if (*list != NULL) {
301 * list of entries found
303 *error = 0;
305 return (nserr);
309 loadmaster_files(char *mastermap, char *defopts, char **stack, char ***stkptr)
311 FILE *fp;
312 int done = 0;
313 char *line, *dir, *map, *opts;
314 char linebuf[LINESZ];
315 char lineq[LINESZ];
316 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
319 if ((fp = file_open(mastermap, fname, stack, stkptr)) == NULL)
320 return (__NSW_UNAVAIL);
322 while ((line = get_line(fp, fname, linebuf,
323 sizeof (linebuf))) != NULL) {
324 unquote(line, lineq);
325 if (macro_expand("", line, lineq, LINESZ)) {
326 syslog(LOG_ERR, "map %s: line too long (max %d chars)",
327 mastermap, LINESZ - 1);
328 continue;
330 dir = line;
331 while (*dir && isspace(*dir))
332 dir++;
333 if (*dir == '\0')
334 continue;
335 map = dir;
337 while (*map && !isspace(*map)) map++;
338 if (*map)
339 *map++ = '\0';
341 if (*dir == '+') {
342 opts = map;
343 while (*opts && isspace(*opts))
344 opts++;
345 if (*opts != '-')
346 opts = defopts;
347 else
348 opts++;
350 * Check for no embedded blanks.
352 if (strcspn(opts, " ") == strlen(opts)) {
353 dir++;
354 (void) loadmaster_map(dir, opts, stack, stkptr);
355 } else {
356 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname);
357 continue;
360 } else {
361 while (*map && isspace(*map))
362 map++;
363 if (*map == '\0')
364 continue;
365 opts = map;
366 while (*opts && !isspace(*opts))
367 opts++;
368 if (*opts) {
369 *opts++ = '\0';
370 while (*opts && isspace(*opts))
371 opts++;
373 if (*opts != '-')
374 opts = defopts;
375 else
376 opts++;
378 * Check for no embedded blanks.
380 if (strcspn(opts, " ") == strlen(opts)) {
381 dirinit(dir, map, opts, 0, stack, stkptr);
382 } else {
383 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname);
384 continue;
387 done++;
390 (void) stack_op(POP, (char *)NULL, stack, stkptr);
391 (void) fclose(fp);
393 return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
397 loaddirect_files(char *map, char *local_map, char *opts,
398 char **stack, char ***stkptr)
400 FILE *fp;
401 int done = 0;
402 char *line, *p1, *p2;
403 char linebuf[LINESZ];
404 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
406 if ((fp = file_open(map, fname, stack, stkptr)) == NULL)
407 return (__NSW_UNAVAIL);
409 while ((line = get_line(fp, fname, linebuf,
410 sizeof (linebuf))) != NULL) {
411 p1 = line;
412 while (*p1 && isspace(*p1))
413 p1++;
414 if (*p1 == '\0')
415 continue;
416 p2 = p1;
417 while (*p2 && !isspace(*p2))
418 p2++;
419 *p2 = '\0';
420 if (*p1 == '+') {
421 p1++;
422 (void) loaddirect_map(p1, local_map, opts, stack,
423 stkptr);
424 } else {
425 dirinit(p1, local_map, opts, 1, stack, stkptr);
427 done++;
430 (void) stack_op(POP, (char *)NULL, stack, stkptr);
431 (void) fclose(fp);
433 return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
437 * This procedure opens the file and pushes it onto the
438 * the stack. Only if a file is opened successfully, is
439 * it pushed onto the stack
441 static FILE *
442 file_open(char *map, char *fname, char **stack, char ***stkptr)
444 FILE *fp;
446 if (*map != '/') {
447 /* prepend an "/etc" */
448 (void) strcpy(fname, "/etc/");
449 (void) strcat(fname, map);
450 } else {
451 (void) strcpy(fname, map);
454 fp = fopen(fname, "r");
456 if (fp != NULL) {
457 if (!stack_op(PUSH, fname, stack, stkptr)) {
458 (void) fclose(fp);
459 return (NULL);
462 return (fp);
466 * reimplemnted to be MT-HOT.
469 stack_op(int op, char *name, char **stack, char ***stkptr)
471 char **ptr = NULL;
472 char **stk_top = &stack[STACKSIZ - 1];
475 * the stackptr points to the next empty slot
476 * for PUSH: put the element and increment stkptr
477 * for POP: decrement stkptr and free
480 switch (op) {
481 case INIT:
482 for (ptr = stack; ptr != stk_top; ptr++)
483 *ptr = (char *)NULL;
484 *stkptr = stack;
485 return (1);
486 case ERASE:
487 for (ptr = stack; ptr != stk_top; ptr++)
488 if (*ptr) {
489 if (trace > 1)
490 trace_prt(1, " ERASE %s\n", *ptr);
491 free (*ptr);
492 *ptr = (char *)NULL;
494 *stkptr = stack;
495 return (1);
496 case PUSH:
497 if (*stkptr == stk_top)
498 return (0);
499 for (ptr = stack; ptr != *stkptr; ptr++)
500 if (*ptr && (strcmp(*ptr, name) == 0)) {
501 return (0);
503 if (trace > 1)
504 trace_prt(1, " PUSH %s\n", name);
505 if ((**stkptr = strdup(name)) == NULL) {
506 syslog(LOG_ERR, "stack_op: Memory alloc failed : %m");
507 return (0);
509 (*stkptr)++;
510 return (1);
511 case POP:
512 if (*stkptr != stack)
513 (*stkptr)--;
514 else
515 syslog(LOG_ERR, "Attempt to pop empty stack\n");
517 if (*stkptr && **stkptr) {
518 if (trace > 1)
519 trace_prt(1, " POP %s\n", **stkptr);
520 free (**stkptr);
521 **stkptr = (char *)NULL;
523 return (1);
524 default:
525 return (0);
529 #define READ_EXECOUT_ARGS 3
532 * read_execout(char *key, char **lp, char *fname, char *line, int linesz)
533 * A simpler, multithreaded implementation of popen(). Used due to
534 * non multithreaded implementation of popen() (it calls vfork()) and a
535 * significant bug in execl().
536 * Returns 0 on OK or -1 on error.
538 static int
539 read_execout(char *key, char **lp, char *fname, char *line, int linesz)
541 int p[2];
542 int status = 0;
543 int child_pid;
544 char *args[READ_EXECOUT_ARGS];
545 FILE *fp0;
547 if (pipe(p) < 0) {
548 syslog(LOG_ERR, "read_execout: Cannot create pipe");
549 return (-1);
552 /* setup args for execv */
553 if (((args[0] = strdup(fname)) == NULL) ||
554 ((args[1] = strdup(key)) == NULL)) {
555 if (args[0] != NULL)
556 free(args[0]);
557 syslog(LOG_ERR, "read_execout: Memory allocation failed");
558 return (-1);
560 args[2] = NULL;
562 if (trace > 3)
563 trace_prt(1, "\tread_execout: forking .....\n");
565 switch ((child_pid = fork1())) {
566 case -1:
567 syslog(LOG_ERR, "read_execout: Cannot fork");
568 return (-1);
569 case 0:
571 * Child
573 close(p[0]);
574 close(1);
575 if (fcntl(p[1], F_DUPFD, 1) != 1) {
576 syslog(LOG_ERR,
577 "read_execout: dup of stdout failed");
578 _exit(-1);
580 close(p[1]);
581 execv(fname, &args[0]);
582 _exit(-1);
583 default:
585 * Parent
587 close(p[1]);
590 * wait for child to complete. Note we read after the
591 * child exits to guarantee a full pipe.
593 while (waitpid(child_pid, &status, 0) < 0) {
594 /* if waitpid fails with EINTR, restart */
595 if (errno != EINTR) {
596 status = -1;
597 break;
600 if (status != -1) {
601 if ((fp0 = fdopen(p[0], "r")) != NULL) {
602 *lp = get_line(fp0, fname, line, linesz);
603 fclose(fp0);
604 } else {
605 close(p[0]);
606 status = -1;
608 } else {
609 close(p[0]);
612 /* free args */
613 free(args[0]);
614 free(args[1]);
616 if (trace > 3) {
617 trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n",
618 fname, key, line);
621 return (status);
625 void
626 automountd_do_exec_map(void *cookie, char *argp, size_t arg_size,
627 door_desc_t *dfd, uint_t n_desc)
629 command_t *command;
630 char line[LINESZ];
631 char *lp;
632 int rc;
634 command = (command_t *)argp;
636 if (sizeof (*command) != arg_size) {
637 rc = 0;
638 syslog(LOG_ERR, "read_execout: invalid door arguments");
639 door_return((char *)&rc, sizeof (rc), NULL, 0);
642 rc = read_execout(command->key, &lp, command->file, line, LINESZ);
644 if (rc != 0) {
646 * read_execout returned an error, return 0 to the door_client
647 * to indicate failure
649 rc = 0;
650 door_return((char *)&rc, sizeof (rc), NULL, 0);
651 } else {
652 door_return((char *)line, LINESZ, NULL, 0);
654 trace_prt(1, "automountd_do_exec_map, door return failed %s, %s\n",
655 command->file, strerror(errno));
656 door_return(NULL, 0, NULL, 0);
659 static int
660 call_read_execout(char *key, char *fname, char *line, int linesz)
662 command_t command;
663 door_arg_t darg;
664 int ret;
666 bzero(&command, sizeof (command));
667 (void) strlcpy(command.file, fname, MAXPATHLEN);
668 (void) strlcpy(command.key, key, MAXOPTSLEN);
670 if (trace >= 1)
671 trace_prt(1, "call_read_execout %s %s\n", fname, key);
672 darg.data_ptr = (char *)&command;
673 darg.data_size = sizeof (command);
674 darg.desc_ptr = NULL;
675 darg.desc_num = 0;
676 darg.rbuf = line;
677 darg.rsize = linesz;
679 ret = door_call(did_exec_map, &darg);
681 return (ret);