dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / autofs / ns_files.c
blobe6b409093a19a75557249b564534dafdc3d18cef
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 *key, char **lp, char *fname, char *line,
50 int linesz);
51 static int call_read_execout(char *key, char **lp, char *fname, char *line,
52 int linesz);
53 static FILE *file_open(char *, char *, char **, char ***);
56 * Initialize the stack
58 void
59 init_files(char **stack, char ***stkptr)
62 * The call is bogus for automountd since the stack is
63 * is more appropriately initialized in the thread-private
64 * routines
66 if (stack == NULL && stkptr == NULL)
67 return;
68 (void) stack_op(INIT, NULL, stack, stkptr);
71 int
72 getmapent_files(key, mapname, ml, stack, stkptr, iswildcard, isrestricted)
73 char *key;
74 char *mapname;
75 struct mapline *ml;
76 char **stack, ***stkptr;
77 bool_t *iswildcard;
78 bool_t isrestricted;
80 int nserr;
81 FILE *fp;
82 char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
83 char linebuf[LINESZ], lineqbuf[LINESZ];
84 char *lp, *lq;
85 struct stat stbuf;
86 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
87 int syntaxok = 1;
89 if (iswildcard)
90 *iswildcard = FALSE;
91 if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) {
92 nserr = __NSW_UNAVAIL;
93 goto done;
96 if (stat(fname, &stbuf) < 0) {
97 nserr = __NSW_UNAVAIL;
98 goto done;
102 * If the file has its execute bit on then
103 * assume it's an executable map.
104 * Execute it and pass the key as an argument.
105 * Expect to get a map entry on the stdout.
106 * Ignore the "x" bit on restricted maps.
108 if (!isrestricted && (stbuf.st_mode & S_IXUSR)) {
109 int rc;
111 if (trace > 1) {
112 trace_prt(1,
113 "\tExecutable map: map=%s key=%s\n",
114 fname, key);
117 rc = call_read_execout(key, &lp, fname, ml->linebuf, LINESZ);
119 if (rc != 0) {
120 nserr = __NSW_UNAVAIL;
121 goto done;
124 if (strlen(ml->linebuf) == 0) {
125 nserr = __NSW_NOTFOUND;
126 goto done;
129 unquote(ml->linebuf, ml->lineqbuf);
130 nserr = __NSW_SUCCESS;
131 goto done;
136 * It's just a normal map file.
137 * Search for the entry with the required key.
139 for (;;) {
140 lp = get_line(fp, fname, linebuf, sizeof (linebuf));
141 if (lp == NULL) {
142 nserr = __NSW_NOTFOUND;
143 goto done;
145 if (verbose && syntaxok && isspace(*(uchar_t *)lp)) {
146 syntaxok = 0;
147 syslog(LOG_ERR,
148 "leading space in map entry \"%s\" in %s",
149 lp, mapname);
151 lq = lineqbuf;
152 unquote(lp, lq);
153 if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word))
154 == -1) || (word[0] == '\0'))
155 continue;
156 if (strcmp(word, key) == 0)
157 break;
158 if (word[0] == '*' && word[1] == '\0') {
159 if (iswildcard)
160 *iswildcard = TRUE;
161 break;
163 if (word[0] == '+') {
164 nserr = getmapent(key, word+1, ml, stack, stkptr,
165 iswildcard, isrestricted);
166 if (nserr == __NSW_SUCCESS)
167 goto done;
168 continue;
172 * sanity check each map entry key against
173 * the lookup key as the map is searched.
175 if (verbose && syntaxok) { /* sanity check entry */
176 if (*key == '/') {
177 if (*word != '/') {
178 syntaxok = 0;
179 syslog(LOG_ERR,
180 "bad key \"%s\" in direct map %s\n",
181 word, mapname);
183 } else {
184 if (strchr(word, '/')) {
185 syntaxok = 0;
186 syslog(LOG_ERR,
187 "bad key \"%s\" in indirect map %s\n",
188 word, mapname);
194 (void) strcpy(ml->linebuf, lp);
195 (void) strcpy(ml->lineqbuf, lq);
196 nserr = __NSW_SUCCESS;
197 done:
198 if (fp) {
199 (void) stack_op(POP, NULL, stack, stkptr);
200 (void) fclose(fp);
204 return (nserr);
208 getmapkeys_files(mapname, list, error, cache_time, stack, stkptr)
209 char *mapname;
210 struct dir_entry **list;
211 int *error;
212 int *cache_time;
213 char **stack, ***stkptr;
215 FILE *fp = NULL;
216 char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
217 char linebuf[LINESZ], lineqbuf[LINESZ];
218 char *lp, *lq;
219 struct stat stbuf;
220 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
221 int syntaxok = 1;
222 int nserr;
223 struct dir_entry *last = NULL;
225 if (trace > 1)
226 trace_prt(1, "getmapkeys_files %s\n", mapname);
228 *cache_time = RDDIR_CACHE_TIME;
229 if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) {
230 *error = ENOENT;
231 nserr = __NSW_UNAVAIL;
232 goto done;
234 if (fseek(fp, 0L, SEEK_SET) == -1) {
235 *error = ENOENT;
236 nserr = __NSW_UNAVAIL;
237 goto done;
240 if (stat(fname, &stbuf) < 0) {
241 *error = ENOENT;
242 nserr = __NSW_UNAVAIL;
243 goto done;
247 * If the file has its execute bit on then
248 * assume it's an executable map.
249 * I don't know how to list executable maps, return
250 * an empty map.
252 if (stbuf.st_mode & S_IXUSR) {
253 *error = 0;
254 nserr = __NSW_SUCCESS;
255 goto done;
258 * It's just a normal map file.
259 * List entries one line at a time.
261 for (;;) {
262 lp = get_line(fp, fname, linebuf, sizeof (linebuf));
263 if (lp == NULL) {
264 nserr = __NSW_SUCCESS;
265 goto done;
267 if (syntaxok && isspace(*(uchar_t *)lp)) {
268 syntaxok = 0;
269 syslog(LOG_ERR,
270 "leading space in map entry \"%s\" in %s",
271 lp, mapname);
273 lq = lineqbuf;
274 unquote(lp, lq);
275 if ((getword(word, wordq, &lp, &lq, ' ', MAXFILENAMELEN)
276 == -1) || (word[0] == '\0'))
277 continue;
279 * Wildcard entries should be ignored and this should be
280 * the last entry read to corroborate the search through
281 * files, i.e., search for key until a wildcard is reached.
283 if (word[0] == '*' && word[1] == '\0')
284 break;
285 if (word[0] == '+') {
287 * Name switch here
289 getmapkeys(word+1, list, error, cache_time,
290 stack, stkptr, 0);
292 * the list may have been updated, therefore
293 * our 'last' may no longer be valid
295 last = NULL;
296 continue;
299 if (add_dir_entry(word, list, &last) != 0) {
300 *error = ENOMEM;
301 goto done;
303 assert(last != NULL);
306 nserr = __NSW_SUCCESS;
307 done:
308 if (fp) {
309 (void) stack_op(POP, NULL, stack, stkptr);
310 (void) fclose(fp);
313 if (*list != NULL) {
315 * list of entries found
317 *error = 0;
319 return (nserr);
323 loadmaster_files(mastermap, defopts, stack, stkptr)
324 char *mastermap;
325 char *defopts;
326 char **stack, ***stkptr;
328 FILE *fp;
329 int done = 0;
330 char *line, *dir, *map, *opts;
331 char linebuf[LINESZ];
332 char lineq[LINESZ];
333 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
336 if ((fp = file_open(mastermap, fname, stack, stkptr)) == NULL)
337 return (__NSW_UNAVAIL);
339 while ((line = get_line(fp, fname, linebuf,
340 sizeof (linebuf))) != NULL) {
341 unquote(line, lineq);
342 if (macro_expand("", line, lineq, LINESZ)) {
343 syslog(LOG_ERR,
344 "map %s: line too long (max %d chars)",
345 mastermap, LINESZ - 1);
346 continue;
348 dir = line;
349 while (*dir && isspace(*dir))
350 dir++;
351 if (*dir == '\0')
352 continue;
353 map = dir;
355 while (*map && !isspace(*map)) map++;
356 if (*map)
357 *map++ = '\0';
359 if (*dir == '+') {
360 opts = map;
361 while (*opts && isspace(*opts))
362 opts++;
363 if (*opts != '-')
364 opts = defopts;
365 else
366 opts++;
368 * Check for no embedded blanks.
370 if (strcspn(opts, " ") == strlen(opts)) {
371 dir++;
372 (void) loadmaster_map(dir, opts, stack, stkptr);
373 } else {
374 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname);
375 continue;
378 } else {
379 while (*map && isspace(*map))
380 map++;
381 if (*map == '\0')
382 continue;
383 opts = map;
384 while (*opts && !isspace(*opts))
385 opts++;
386 if (*opts) {
387 *opts++ = '\0';
388 while (*opts && isspace(*opts))
389 opts++;
391 if (*opts != '-')
392 opts = defopts;
393 else
394 opts++;
396 * Check for no embedded blanks.
398 if (strcspn(opts, " ") == strlen(opts)) {
399 dirinit(dir, map, opts, 0, stack, stkptr);
400 } else {
401 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname);
402 continue;
405 done++;
408 (void) stack_op(POP, NULL, stack, stkptr);
409 (void) fclose(fp);
411 return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
415 loaddirect_files(map, local_map, opts, stack, stkptr)
416 char *map, *local_map, *opts;
417 char **stack, ***stkptr;
419 FILE *fp;
420 int done = 0;
421 char *line, *p1, *p2;
422 char linebuf[LINESZ];
423 char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
425 if ((fp = file_open(map, fname, stack, stkptr)) == NULL)
426 return (__NSW_UNAVAIL);
428 while ((line = get_line(fp, fname, linebuf,
429 sizeof (linebuf))) != NULL) {
430 p1 = line;
431 while (*p1 && isspace(*p1))
432 p1++;
433 if (*p1 == '\0')
434 continue;
435 p2 = p1;
436 while (*p2 && !isspace(*p2))
437 p2++;
438 *p2 = '\0';
439 if (*p1 == '+') {
440 p1++;
441 (void) loaddirect_map(p1, local_map, opts, stack,
442 stkptr);
443 } else {
444 dirinit(p1, local_map, opts, 1, stack, stkptr);
446 done++;
449 (void) stack_op(POP, NULL, stack, stkptr);
450 (void) fclose(fp);
452 return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
456 * This procedure opens the file and pushes it onto the
457 * the stack. Only if a file is opened successfully, is
458 * it pushed onto the stack
460 static FILE *
461 file_open(map, fname, stack, stkptr)
462 char *map, *fname;
463 char **stack, ***stkptr;
465 FILE *fp;
467 if (*map != '/') {
468 /* prepend an "/etc" */
469 (void) strcpy(fname, "/etc/");
470 (void) strcat(fname, map);
471 } else
472 (void) strcpy(fname, map);
474 fp = fopen(fname, "r");
476 if (fp != NULL) {
477 if (!stack_op(PUSH, fname, stack, stkptr)) {
478 (void) fclose(fp);
479 return (NULL);
482 return (fp);
486 * reimplemnted to be MT-HOT.
489 stack_op(op, name, stack, stkptr)
490 int op;
491 char *name;
492 char **stack, ***stkptr;
494 char **ptr = NULL;
495 char **stk_top = &stack[STACKSIZ - 1];
498 * the stackptr points to the next empty slot
499 * for PUSH: put the element and increment stkptr
500 * for POP: decrement stkptr and free
503 switch (op) {
504 case INIT:
505 for (ptr = stack; ptr != stk_top; ptr++)
506 *ptr = NULL;
507 *stkptr = stack;
508 return (1);
509 case ERASE:
510 for (ptr = stack; ptr != stk_top; ptr++)
511 if (*ptr) {
512 if (trace > 1)
513 trace_prt(1, " ERASE %s\n", *ptr);
514 free (*ptr);
515 *ptr = NULL;
517 *stkptr = stack;
518 return (1);
519 case PUSH:
520 if (*stkptr == stk_top)
521 return (0);
522 for (ptr = stack; ptr != *stkptr; ptr++)
523 if (*ptr && (strcmp(*ptr, name) == 0)) {
524 return (0);
526 if (trace > 1)
527 trace_prt(1, " PUSH %s\n", name);
528 if ((**stkptr = strdup(name)) == NULL) {
529 syslog(LOG_ERR, "stack_op: Memory alloc failed : %m");
530 return (0);
532 (*stkptr)++;
533 return (1);
534 case POP:
535 if (*stkptr != stack)
536 (*stkptr)--;
537 else
538 syslog(LOG_ERR, "Attempt to pop empty stack\n");
540 if (*stkptr && **stkptr) {
541 if (trace > 1)
542 trace_prt(1, " POP %s\n", **stkptr);
543 free (**stkptr);
544 **stkptr = NULL;
546 return (1);
547 default:
548 return (0);
552 #define READ_EXECOUT_ARGS 3
555 * read_execout(char *key, char **lp, char *fname, char *line, int linesz)
556 * A simpler, multithreaded implementation of popen(). Used due to
557 * non multithreaded implementation of popen() (it calls vfork()) and a
558 * significant bug in execl().
559 * Returns 0 on OK or -1 on error.
561 static int
562 read_execout(char *key, char **lp, char *fname, char *line, int linesz)
564 int p[2];
565 int status = 0;
566 int child_pid;
567 char *args[READ_EXECOUT_ARGS];
568 FILE *fp0;
570 if (pipe(p) < 0) {
571 syslog(LOG_ERR, "read_execout: Cannot create pipe");
572 return (-1);
575 /* setup args for execv */
576 if (((args[0] = strdup(fname)) == NULL) ||
577 ((args[1] = strdup(key)) == NULL)) {
578 free(args[0]);
579 syslog(LOG_ERR, "read_execout: Memory allocation failed");
580 return (-1);
582 args[2] = NULL;
584 if (trace > 3)
585 trace_prt(1, "\tread_execout: forking .....\n");
587 switch ((child_pid = fork1())) {
588 case -1:
589 syslog(LOG_ERR, "read_execout: Cannot fork");
590 return (-1);
591 case 0:
593 * Child
595 close(p[0]);
596 close(1);
597 if (fcntl(p[1], F_DUPFD, 1) != 1) {
598 syslog(LOG_ERR,
599 "read_execout: dup of stdout failed");
600 _exit(-1);
602 close(p[1]);
603 execv(fname, &args[0]);
604 _exit(-1);
605 default:
607 * Parent
609 close(p[1]);
612 * wait for child to complete. Note we read after the
613 * child exits to guarantee a full pipe.
615 while (waitpid(child_pid, &status, 0) < 0) {
616 /* if waitpid fails with EINTR, restart */
617 if (errno != EINTR) {
618 status = -1;
619 break;
622 if (status != -1) {
623 if ((fp0 = fdopen(p[0], "r")) != NULL) {
624 *lp = get_line(fp0, fname, line, linesz);
625 fclose(fp0);
626 } else {
627 close(p[0]);
628 status = -1;
630 } else {
631 close(p[0]);
634 /* free args */
635 free(args[0]);
636 free(args[1]);
638 if (trace > 3)
639 trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n",
640 fname, key, line);
642 return (status);
646 void
647 automountd_do_exec_map(void *cookie, char *argp, size_t arg_size,
648 door_desc_t *dfd, uint_t n_desc)
650 command_t *command;
651 char line[LINESZ];
652 char *lp;
653 int rc;
655 command = (command_t *)argp;
657 if (sizeof (*command) != arg_size) {
658 rc = 0;
659 syslog(LOG_ERR, "read_execout: invalid door arguments");
660 door_return((char *)&rc, sizeof (rc), NULL, 0);
663 rc = read_execout(command->key, &lp, command->file, line, LINESZ);
665 if (rc != 0) {
667 * read_execout returned an error, return 0 to the door_client
668 * to indicate failure
670 rc = 0;
671 door_return((char *)&rc, sizeof (rc), NULL, 0);
672 } else {
673 door_return((char *)line, LINESZ, NULL, 0);
675 trace_prt(1, "automountd_do_exec_map, door return failed %s, %s\n",
676 command->file, strerror(errno));
677 door_return(NULL, 0, NULL, 0);
681 call_read_execout(char *key, char **lp, char *fname, char *line,
682 int linesz)
684 command_t command;
685 door_arg_t darg;
686 int ret;
688 bzero(&command, sizeof (command));
689 (void) strlcpy(command.file, fname, MAXPATHLEN);
690 (void) strlcpy(command.key, key, MAXOPTSLEN);
692 if (trace >= 1)
693 trace_prt(1, "call_read_execout %s %s\n", fname, key);
694 darg.data_ptr = (char *)&command;
695 darg.data_size = sizeof (command);
696 darg.desc_ptr = NULL;
697 darg.desc_num = 0;
698 darg.rbuf = line;
699 darg.rsize = linesz;
701 ret = door_call(did_exec_map, &darg);
703 lp = &line;
704 return (ret);