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]
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #pragma ident "%Z%%M% %I% %E% SMI"
37 #include <sys/param.h>
39 #include <rpcsvc/nfs_prot.h>
46 #include <sys/types.h>
49 #include "automount.h"
51 static int read_execout(char *key
, char **lp
, char *fname
, char *line
,
53 static int call_read_execout(char *key
, char **lp
, char *fname
, char *line
,
55 static FILE *file_open(char *, char *, char **, char ***);
58 * Initialize the stack
61 init_files(char **stack
, char ***stkptr
)
64 * The call is bogus for automountd since the stack is
65 * is more appropriately initialized in the thread-private
68 if (stack
== NULL
&& stkptr
== NULL
)
70 (void) stack_op(INIT
, NULL
, stack
, stkptr
);
74 getmapent_files(key
, mapname
, ml
, stack
, stkptr
, iswildcard
, isrestricted
)
78 char **stack
, ***stkptr
;
84 char word
[MAXPATHLEN
+1], wordq
[MAXPATHLEN
+1];
85 char linebuf
[LINESZ
], lineqbuf
[LINESZ
];
88 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
93 if ((fp
= file_open(mapname
, fname
, stack
, stkptr
)) == NULL
) {
94 nserr
= __NSW_UNAVAIL
;
98 if (stat(fname
, &stbuf
) < 0) {
99 nserr
= __NSW_UNAVAIL
;
104 * If the file has its execute bit on then
105 * assume it's an executable map.
106 * Execute it and pass the key as an argument.
107 * Expect to get a map entry on the stdout.
108 * Ignore the "x" bit on restricted maps.
110 if (!isrestricted
&& (stbuf
.st_mode
& S_IXUSR
)) {
115 "\tExecutable map: map=%s key=%s\n",
119 rc
= call_read_execout(key
, &lp
, fname
, ml
->linebuf
, LINESZ
);
122 nserr
= __NSW_UNAVAIL
;
126 if (strlen(ml
->linebuf
) == 0) {
127 nserr
= __NSW_NOTFOUND
;
131 unquote(ml
->linebuf
, ml
->lineqbuf
);
132 nserr
= __NSW_SUCCESS
;
138 * It's just a normal map file.
139 * Search for the entry with the required key.
142 lp
= get_line(fp
, fname
, linebuf
, sizeof (linebuf
));
144 nserr
= __NSW_NOTFOUND
;
147 if (verbose
&& syntaxok
&& isspace(*(uchar_t
*)lp
)) {
150 "leading space in map entry \"%s\" in %s",
155 if ((getword(word
, wordq
, &lp
, &lq
, ' ', sizeof (word
))
156 == -1) || (word
[0] == '\0'))
158 if (strcmp(word
, key
) == 0)
160 if (word
[0] == '*' && word
[1] == '\0') {
165 if (word
[0] == '+') {
166 nserr
= getmapent(key
, word
+1, ml
, stack
, stkptr
,
167 iswildcard
, isrestricted
);
168 if (nserr
== __NSW_SUCCESS
)
174 * sanity check each map entry key against
175 * the lookup key as the map is searched.
177 if (verbose
&& syntaxok
) { /* sanity check entry */
182 "bad key \"%s\" in direct map %s\n",
186 if (strchr(word
, '/')) {
189 "bad key \"%s\" in indirect map %s\n",
196 (void) strcpy(ml
->linebuf
, lp
);
197 (void) strcpy(ml
->lineqbuf
, lq
);
198 nserr
= __NSW_SUCCESS
;
201 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
210 getmapkeys_files(mapname
, list
, error
, cache_time
, stack
, stkptr
)
212 struct dir_entry
**list
;
215 char **stack
, ***stkptr
;
218 char word
[MAXPATHLEN
+1], wordq
[MAXPATHLEN
+1];
219 char linebuf
[LINESZ
], lineqbuf
[LINESZ
];
222 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
225 struct dir_entry
*last
= NULL
;
228 trace_prt(1, "getmapkeys_files %s\n", mapname
);
230 *cache_time
= RDDIR_CACHE_TIME
;
231 if ((fp
= file_open(mapname
, fname
, stack
, stkptr
)) == NULL
) {
233 nserr
= __NSW_UNAVAIL
;
236 if (fseek(fp
, 0L, SEEK_SET
) == -1) {
238 nserr
= __NSW_UNAVAIL
;
242 if (stat(fname
, &stbuf
) < 0) {
244 nserr
= __NSW_UNAVAIL
;
249 * If the file has its execute bit on then
250 * assume it's an executable map.
251 * I don't know how to list executable maps, return
254 if (stbuf
.st_mode
& S_IXUSR
) {
256 nserr
= __NSW_SUCCESS
;
260 * It's just a normal map file.
261 * List entries one line at a time.
264 lp
= get_line(fp
, fname
, linebuf
, sizeof (linebuf
));
266 nserr
= __NSW_SUCCESS
;
269 if (syntaxok
&& isspace(*(uchar_t
*)lp
)) {
272 "leading space in map entry \"%s\" in %s",
277 if ((getword(word
, wordq
, &lp
, &lq
, ' ', MAXFILENAMELEN
)
278 == -1) || (word
[0] == '\0'))
281 * Wildcard entries should be ignored and this should be
282 * the last entry read to corroborate the search through
283 * files, i.e., search for key until a wildcard is reached.
285 if (word
[0] == '*' && word
[1] == '\0')
287 if (word
[0] == '+') {
291 getmapkeys(word
+1, list
, error
, cache_time
,
294 * the list may have been updated, therefore
295 * our 'last' may no longer be valid
301 if (add_dir_entry(word
, list
, &last
) != 0) {
305 assert(last
!= NULL
);
308 nserr
= __NSW_SUCCESS
;
311 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
317 * list of entries found
325 loadmaster_files(mastermap
, defopts
, stack
, stkptr
)
328 char **stack
, ***stkptr
;
332 char *line
, *dir
, *map
, *opts
;
333 char linebuf
[LINESZ
];
335 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
338 if ((fp
= file_open(mastermap
, fname
, stack
, stkptr
)) == NULL
)
339 return (__NSW_UNAVAIL
);
341 while ((line
= get_line(fp
, fname
, linebuf
,
342 sizeof (linebuf
))) != NULL
) {
343 unquote(line
, lineq
);
344 if (macro_expand("", line
, lineq
, LINESZ
)) {
346 "map %s: line too long (max %d chars)",
347 mastermap
, LINESZ
- 1);
351 while (*dir
&& isspace(*dir
))
357 while (*map
&& !isspace(*map
)) map
++;
363 while (*opts
&& isspace(*opts
))
370 * Check for no embedded blanks.
372 if (strcspn(opts
, " ") == strlen(opts
)) {
374 (void) loadmaster_map(dir
, opts
, stack
, stkptr
);
376 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir
, fname
);
381 while (*map
&& isspace(*map
))
386 while (*opts
&& !isspace(*opts
))
390 while (*opts
&& isspace(*opts
))
398 * Check for no embedded blanks.
400 if (strcspn(opts
, " ") == strlen(opts
)) {
401 dirinit(dir
, map
, opts
, 0, stack
, stkptr
);
403 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir
, fname
);
410 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
413 return (done
? __NSW_SUCCESS
: __NSW_NOTFOUND
);
417 loaddirect_files(map
, local_map
, opts
, stack
, stkptr
)
418 char *map
, *local_map
, *opts
;
419 char **stack
, ***stkptr
;
423 char *line
, *p1
, *p2
;
424 char linebuf
[LINESZ
];
425 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
427 if ((fp
= file_open(map
, fname
, stack
, stkptr
)) == NULL
)
428 return (__NSW_UNAVAIL
);
430 while ((line
= get_line(fp
, fname
, linebuf
,
431 sizeof (linebuf
))) != NULL
) {
433 while (*p1
&& isspace(*p1
))
438 while (*p2
&& !isspace(*p2
))
443 (void) loaddirect_map(p1
, local_map
, opts
, stack
,
446 dirinit(p1
, local_map
, opts
, 1, stack
, stkptr
);
451 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
454 return (done
? __NSW_SUCCESS
: __NSW_NOTFOUND
);
458 * This procedure opens the file and pushes it onto the
459 * the stack. Only if a file is opened successfully, is
460 * it pushed onto the stack
463 file_open(map
, fname
, stack
, stkptr
)
465 char **stack
, ***stkptr
;
470 /* prepend an "/etc" */
471 (void) strcpy(fname
, "/etc/");
472 (void) strcat(fname
, map
);
474 (void) strcpy(fname
, map
);
476 fp
= fopen(fname
, "r");
479 if (!stack_op(PUSH
, fname
, stack
, stkptr
)) {
488 * reimplemnted to be MT-HOT.
491 stack_op(op
, name
, stack
, stkptr
)
494 char **stack
, ***stkptr
;
497 char **stk_top
= &stack
[STACKSIZ
- 1];
500 * the stackptr points to the next empty slot
501 * for PUSH: put the element and increment stkptr
502 * for POP: decrement stkptr and free
507 for (ptr
= stack
; ptr
!= stk_top
; ptr
++)
512 for (ptr
= stack
; ptr
!= stk_top
; ptr
++)
515 trace_prt(1, " ERASE %s\n", *ptr
);
522 if (*stkptr
== stk_top
)
524 for (ptr
= stack
; ptr
!= *stkptr
; ptr
++)
525 if (*ptr
&& (strcmp(*ptr
, name
) == 0)) {
529 trace_prt(1, " PUSH %s\n", name
);
530 if ((**stkptr
= strdup(name
)) == NULL
) {
531 syslog(LOG_ERR
, "stack_op: Memory alloc failed : %m");
537 if (*stkptr
!= stack
)
540 syslog(LOG_ERR
, "Attempt to pop empty stack\n");
542 if (*stkptr
&& **stkptr
) {
544 trace_prt(1, " POP %s\n", **stkptr
);
546 **stkptr
= (char *)NULL
;
554 #define READ_EXECOUT_ARGS 3
557 * read_execout(char *key, char **lp, char *fname, char *line, int linesz)
558 * A simpler, multithreaded implementation of popen(). Used due to
559 * non multithreaded implementation of popen() (it calls vfork()) and a
560 * significant bug in execl().
561 * Returns 0 on OK or -1 on error.
564 read_execout(char *key
, char **lp
, char *fname
, char *line
, int linesz
)
569 char *args
[READ_EXECOUT_ARGS
];
573 syslog(LOG_ERR
, "read_execout: Cannot create pipe");
577 /* setup args for execv */
578 if (((args
[0] = strdup(fname
)) == NULL
) ||
579 ((args
[1] = strdup(key
)) == NULL
)) {
582 syslog(LOG_ERR
, "read_execout: Memory allocation failed");
588 trace_prt(1, "\tread_execout: forking .....\n");
590 switch ((child_pid
= fork1())) {
592 syslog(LOG_ERR
, "read_execout: Cannot fork");
600 if (fcntl(p
[1], F_DUPFD
, 1) != 1) {
602 "read_execout: dup of stdout failed");
606 execv(fname
, &args
[0]);
615 * wait for child to complete. Note we read after the
616 * child exits to guarantee a full pipe.
618 while (waitpid(child_pid
, &status
, 0) < 0) {
619 /* if waitpid fails with EINTR, restart */
620 if (errno
!= EINTR
) {
626 if ((fp0
= fdopen(p
[0], "r")) != NULL
) {
627 *lp
= get_line(fp0
, fname
, line
, linesz
);
642 trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n",
650 automountd_do_exec_map(void *cookie
, char *argp
, size_t arg_size
,
651 door_desc_t
*dfd
, uint_t n_desc
)
658 command
= (command_t
*)argp
;
660 if (sizeof (*command
) != arg_size
) {
662 syslog(LOG_ERR
, "read_execout: invalid door arguments");
663 door_return((char *)&rc
, sizeof (rc
), NULL
, 0);
666 rc
= read_execout(command
->key
, &lp
, command
->file
, line
, LINESZ
);
670 * read_execout returned an error, return 0 to the door_client
671 * to indicate failure
674 door_return((char *)&rc
, sizeof (rc
), NULL
, 0);
676 door_return((char *)line
, LINESZ
, NULL
, 0);
678 trace_prt(1, "automountd_do_exec_map, door return failed %s, %s\n",
679 command
->file
, strerror(errno
));
680 door_return(NULL
, 0, NULL
, 0);
684 call_read_execout(char *key
, char **lp
, char *fname
, char *line
,
691 bzero(&command
, sizeof (command
));
692 (void) strlcpy(command
.file
, fname
, MAXPATHLEN
);
693 (void) strlcpy(command
.key
, key
, MAXOPTSLEN
);
696 trace_prt(1, "call_read_execout %s %s\n", fname
, key
);
697 darg
.data_ptr
= (char *)&command
;
698 darg
.data_size
= sizeof (command
);
699 darg
.desc_ptr
= NULL
;
704 ret
= door_call(did_exec_map
, &darg
);