Mercurial > illumos > onarm
annotate usr/src/cmd/fs.d/autofs/autod_main.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
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. | |
7 * | |
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. | |
12 * | |
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] | |
18 * | |
19 * CDDL HEADER END | |
20 */ | |
21 /* | |
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. | |
23 * Use is subject to license terms. | |
24 */ | |
25 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
26 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 27 |
28 #include <stdio.h> | |
29 #include <stdio_ext.h> | |
30 #include <stdlib.h> | |
31 #include <unistd.h> | |
32 #include <signal.h> | |
33 #include <sys/types.h> | |
34 #include <memory.h> | |
35 #include <stropts.h> | |
36 #include <netconfig.h> | |
37 #include <stdarg.h> | |
38 #include <sys/resource.h> | |
39 #include <sys/systeminfo.h> | |
40 #include <syslog.h> | |
41 #include <errno.h> | |
42 #include <sys/sockio.h> | |
43 #include <rpc/xdr.h> | |
44 #include <net/if.h> | |
45 #include <netdir.h> | |
46 #include <string.h> | |
47 #include <thread.h> | |
48 #include <locale.h> | |
49 #include <door.h> | |
50 #include "automount.h" | |
51 #include <sys/vfs.h> | |
52 #include <sys/mnttab.h> | |
53 #include <arpa/inet.h> | |
54 #include <rpcsvc/daemon_utils.h> | |
55 #include <deflt.h> | |
56 #include <strings.h> | |
57 #include <priv.h> | |
58 #include <tsol/label.h> | |
59 #include <sys/utsname.h> | |
60 #include <sys/thread.h> | |
61 #include <nfs/rnode.h> | |
62 #include <nfs/nfs.h> | |
63 #include <wait.h> | |
64 | |
65 static void autofs_doorfunc(void *, char *, size_t, door_desc_t *, uint_t); | |
66 static void autofs_setdoor(int); | |
67 static void autofs_mntinfo_1_r(autofs_lookupargs *, autofs_mountres *); | |
68 static void autofs_mount_1_free_r(struct autofs_mountres *); | |
69 static void autofs_lookup_1_r(autofs_lookupargs *, autofs_lookupres *); | |
70 static void autofs_lookup_1_free_args(autofs_lookupargs *); | |
71 static void autofs_unmount_1_r(umntrequest *, umntres *); | |
72 static void autofs_unmount_1_free_args(umntrequest *); | |
73 static void autofs_readdir_1_r(autofs_rddirargs *, autofs_rddirres *); | |
74 static void autofs_readdir_1_free_r(struct autofs_rddirres *); | |
75 static int decode_args(xdrproc_t, autofs_door_args_t *, caddr_t *, int); | |
76 static bool_t encode_res(xdrproc_t, autofs_door_res_t **, caddr_t, int *); | |
77 static void usage(); | |
78 static void warn_hup(int); | |
79 static void free_action_list(); | |
80 static int start_autofs_svcs(); | |
81 static void automountd_wait_for_cleanup(pid_t); | |
82 | |
83 /* | |
84 * Private autofs system call | |
85 */ | |
86 extern int _autofssys(int, void *); | |
87 | |
88 #define CTIME_BUF_LEN 26 | |
89 | |
90 #define RESOURCE_FACTOR 8 | |
91 #ifdef DEBUG | |
92 #define AUTOFS_DOOR "/var/run/autofs_door" | |
93 #endif /* DEBUG */ | |
94 | |
95 static thread_key_t s_thr_key; | |
96 | |
97 struct autodir *dir_head; | |
98 struct autodir *dir_tail; | |
99 char self[64]; | |
100 | |
101 time_t timenow; | |
102 int verbose = 0; | |
103 int trace = 0; | |
104 int automountd_nobrowse = 0; | |
105 | |
106 int | |
107 main(argc, argv) | |
108 int argc; | |
109 char *argv[]; | |
110 | |
111 { | |
112 pid_t pid; | |
113 int c, error; | |
114 struct rlimit rlset; | |
115 char *defval; | |
116 | |
117 if (geteuid() != 0) { | |
118 (void) fprintf(stderr, "%s must be run as root\n", argv[0]); | |
119 exit(1); | |
120 } | |
121 | |
122 /* | |
123 * Read in the values from config file first before we check | |
124 * commandline options so the options override the file. | |
125 */ | |
126 if ((defopen(AUTOFSADMIN)) == 0) { | |
127 if ((defval = defread("AUTOMOUNTD_VERBOSE=")) != NULL) { | |
128 if (strncasecmp("true", defval, 4) == 0) | |
129 verbose = TRUE; | |
130 else | |
131 verbose = FALSE; | |
132 } | |
133 if ((defval = defread("AUTOMOUNTD_NOBROWSE=")) != NULL) { | |
134 if (strncasecmp("true", defval, 4) == 0) | |
135 automountd_nobrowse = TRUE; | |
136 else | |
137 automountd_nobrowse = FALSE; | |
138 } | |
139 if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) { | |
140 errno = 0; | |
141 trace = strtol(defval, (char **)NULL, 10); | |
142 if (errno != 0) | |
143 trace = 0; | |
144 } | |
145 put_automountd_env(); | |
146 | |
147 /* close defaults file */ | |
148 defopen(NULL); | |
149 } | |
150 | |
151 while ((c = getopt(argc, argv, "vnTD:")) != EOF) { | |
152 switch (c) { | |
153 case 'v': | |
154 verbose++; | |
155 break; | |
156 case 'n': | |
157 automountd_nobrowse++; | |
158 break; | |
159 case 'T': | |
160 trace++; | |
161 break; | |
162 case 'D': | |
163 (void) putenv(optarg); | |
164 break; | |
165 default: | |
166 usage(); | |
167 } | |
168 } | |
169 | |
170 if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) { | |
171 error = errno; | |
172 (void) fprintf(stderr, | |
173 "automountd: can't determine hostname, error: %d\n", | |
174 error); | |
175 exit(1); | |
176 } | |
177 | |
178 #ifndef DEBUG | |
179 pid = fork(); | |
180 if (pid < 0) { | |
181 perror("cannot fork"); | |
182 exit(1); | |
183 } | |
184 if (pid) | |
185 exit(0); | |
186 #endif | |
187 | |
188 (void) setsid(); | |
189 openlog("automountd", LOG_PID, LOG_DAEMON); | |
190 (void) setlocale(LC_ALL, ""); | |
191 | |
192 /* | |
193 * Create the door_servers to manage fork/exec requests for | |
194 * mounts and executable automount maps | |
195 */ | |
196 if ((did_fork_exec = door_create(automountd_do_fork_exec, | |
197 NULL, NULL)) == -1) { | |
198 syslog(LOG_ERR, "door_create failed: %m, Exiting."); | |
199 exit(errno); | |
200 } | |
201 if ((did_exec_map = door_create(automountd_do_exec_map, | |
202 NULL, NULL)) == -1) { | |
203 syslog(LOG_ERR, "door_create failed: %m, Exiting."); | |
204 if (door_revoke(did_fork_exec) == -1) { | |
205 syslog(LOG_ERR, "failed to door_revoke(%d) %m", | |
206 did_fork_exec); | |
207 } | |
208 exit(errno); | |
209 } | |
210 /* | |
211 * Before we become multithreaded we fork allowing the parent | |
212 * to become a door server to handle all mount and unmount | |
213 * requests. This works around a potential hang in using | |
214 * fork1() within a multithreaded environment | |
215 */ | |
216 | |
217 pid = fork1(); | |
218 if (pid < 0) { | |
219 syslog(LOG_ERR, | |
220 "can't fork the automountd mount process %m"); | |
221 if (door_revoke(did_fork_exec) == -1) { | |
222 syslog(LOG_ERR, "failed to door_revoke(%d) %m", | |
223 did_fork_exec); | |
224 } | |
225 if (door_revoke(did_exec_map) == -1) { | |
226 syslog(LOG_ERR, "failed to door_revoke(%d) %m", | |
227 did_exec_map); | |
228 } | |
229 exit(1); | |
230 } else if (pid > 0) { | |
231 /* this is the door server process */ | |
232 automountd_wait_for_cleanup(pid); | |
233 } | |
234 | |
235 | |
236 (void) rwlock_init(&cache_lock, USYNC_THREAD, NULL); | |
237 (void) rwlock_init(&autofs_rddir_cache_lock, USYNC_THREAD, NULL); | |
238 | |
239 /* | |
240 * initialize the name services, use NULL arguments to ensure | |
241 * we don't initialize the stack of files used in file service | |
242 */ | |
243 (void) ns_setup(NULL, NULL); | |
244 | |
245 /* | |
246 * we're using doors and its thread management now so we need to | |
247 * make sure we have more than the default of 256 file descriptors | |
248 * available. | |
249 */ | |
250 rlset.rlim_cur = RLIM_INFINITY; | |
251 rlset.rlim_max = RLIM_INFINITY; | |
252 if (setrlimit(RLIMIT_NOFILE, &rlset) == -1) | |
253 syslog(LOG_ERR, "setrlimit failed for %s: %s", AUTOMOUNTD, | |
254 strerror(errno)); | |
255 | |
256 (void) enable_extended_FILE_stdio(-1, -1); | |
257 | |
258 /* | |
259 * establish our lock on the lock file and write our pid to it. | |
260 * exit if some other process holds the lock, or if there's any | |
261 * error in writing/locking the file. | |
262 */ | |
263 pid = _enter_daemon_lock(AUTOMOUNTD); | |
264 switch (pid) { | |
265 case 0: | |
266 break; | |
267 case -1: | |
268 syslog(LOG_ERR, "error locking for %s: %m", AUTOMOUNTD); | |
269 exit(2); | |
270 default: | |
271 /* daemon was already running */ | |
272 exit(0); | |
273 } | |
274 | |
275 /* | |
276 * If we coredump it'll be /core. | |
277 */ | |
278 if (chdir("/") < 0) | |
279 syslog(LOG_ERR, "chdir /: %m"); | |
280 | |
281 /* | |
282 * Create cache_cleanup thread | |
283 */ | |
284 if (thr_create(NULL, 0, (void *(*)(void *))cache_cleanup, NULL, | |
285 THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) { | |
286 syslog(LOG_ERR, "unable to create cache_cleanup thread"); | |
287 exit(1); | |
288 } | |
289 | |
290 /* other initializations */ | |
291 (void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL); | |
292 | |
293 /* | |
294 * On a labeled system, allow read-down nfs mounts if privileged | |
295 * (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error | |
296 * and "mount equal label only" behavior will result. | |
297 */ | |
298 if (is_system_labeled()) { | |
299 (void) setpflags(NET_MAC_AWARE, 1); | |
300 (void) setpflags(NET_MAC_AWARE_INHERIT, 1); | |
301 } | |
302 | |
303 (void) signal(SIGHUP, warn_hup); | |
304 | |
305 /* start services */ | |
306 return (start_autofs_svcs()); | |
307 | |
308 } | |
309 | |
310 /* | |
311 * The old automounter supported a SIGHUP | |
312 * to allow it to resynchronize internal | |
313 * state with the /etc/mnttab. | |
314 * This is no longer relevant, but we | |
315 * need to catch the signal and warn | |
316 * the user. | |
317 */ | |
318 /* ARGSUSED */ | |
319 static void | |
320 warn_hup(i) | |
321 int i; | |
322 { | |
323 syslog(LOG_ERR, "SIGHUP received: ignored"); | |
324 (void) signal(SIGHUP, warn_hup); | |
325 } | |
326 | |
327 static void | |
328 usage() | |
329 { | |
330 (void) fprintf(stderr, "Usage: automountd\n" | |
331 "\t[-T]\t\t(trace requests)\n" | |
332 "\t[-v]\t\t(verbose error msgs)\n" | |
333 "\t[-D n=s]\t(define env variable)\n"); | |
334 exit(1); | |
335 /* NOTREACHED */ | |
336 } | |
337 | |
338 static void | |
339 autofs_readdir_1_r( | |
340 autofs_rddirargs *req, | |
341 autofs_rddirres *res) | |
342 { | |
343 if (trace > 0) | |
344 trace_prt(1, "READDIR REQUEST : %s @ %ld\n", | |
345 req->rda_map, req->rda_offset); | |
346 | |
347 do_readdir(req, res); | |
348 if (trace > 0) | |
349 trace_prt(1, "READDIR REPLY : status=%d\n", res->rd_status); | |
350 } | |
351 | |
352 static void | |
353 autofs_readdir_1_free_r(struct autofs_rddirres *res) | |
354 { | |
355 if (res->rd_status == AUTOFS_OK) { | |
356 if (res->rd_rddir.rddir_entries) | |
357 free(res->rd_rddir.rddir_entries); | |
358 } | |
359 } | |
360 | |
361 | |
362 /* ARGSUSED */ | |
363 static void | |
364 autofs_unmount_1_r( | |
365 umntrequest *m, | |
366 umntres *res) | |
367 { | |
368 struct umntrequest *ul; | |
369 | |
370 if (trace > 0) { | |
371 char ctime_buf[CTIME_BUF_LEN]; | |
372 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) | |
373 ctime_buf[0] = '\0'; | |
374 | |
375 trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf); | |
376 for (ul = m; ul; ul = ul->next) | |
377 trace_prt(1, " resource=%s fstype=%s mntpnt=%s" | |
378 " mntopts=%s %s\n", | |
379 ul->mntresource, | |
380 ul->fstype, | |
381 ul->mntpnt, | |
382 ul->mntopts, | |
383 ul->isdirect ? "direct" : "indirect"); | |
384 } | |
385 | |
386 | |
387 res->status = do_unmount1(m); | |
388 | |
389 if (trace > 0) | |
390 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status); | |
391 } | |
392 | |
393 static void | |
394 autofs_lookup_1_r( | |
395 autofs_lookupargs *m, | |
396 autofs_lookupres *res) | |
397 { | |
398 autofs_action_t action; | |
399 struct linka link; | |
400 int status; | |
401 | |
402 if (trace > 0) { | |
403 char ctime_buf[CTIME_BUF_LEN]; | |
404 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) | |
405 ctime_buf[0] = '\0'; | |
406 | |
407 trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf); | |
408 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", | |
409 m->name, m->subdir, m->map, m->opts, m->path, m->isdirect); | |
410 } | |
411 | |
412 bzero(&link, sizeof (struct linka)); | |
413 | |
414 status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path, | |
415 (uint_t)m->isdirect, m->uid, &action, &link); | |
416 if (status == 0) { | |
417 /* | |
418 * Return action list to kernel. | |
419 */ | |
420 res->lu_res = AUTOFS_OK; | |
421 if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) { | |
422 res->lu_type.lookup_result_type_u.lt_linka = link; | |
423 } | |
424 } else { | |
425 /* | |
426 * Entry not found | |
427 */ | |
428 res->lu_res = AUTOFS_NOENT; | |
429 } | |
430 res->lu_verbose = verbose; | |
431 | |
432 if (trace > 0) | |
433 trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res); | |
434 } | |
435 | |
436 static void | |
437 autofs_mntinfo_1_r( | |
438 autofs_lookupargs *m, | |
439 autofs_mountres *res) | |
440 { | |
441 int status; | |
442 action_list *alp = NULL; | |
443 | |
444 if (trace > 0) { | |
445 char ctime_buf[CTIME_BUF_LEN]; | |
446 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) | |
447 ctime_buf[0] = '\0'; | |
448 | |
449 trace_prt(1, "MOUNT REQUEST: %s", ctime_buf); | |
450 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", | |
451 m->name, m->subdir, m->map, m->opts, m->path, m->isdirect); | |
452 } | |
453 | |
454 status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path, | |
455 (uint_t)m->isdirect, m->uid, &alp, DOMOUNT_USER); | |
456 if (status != 0) { | |
457 /* | |
458 * An error occurred, free action list if allocated. | |
459 */ | |
460 if (alp != NULL) { | |
461 free_action_list(alp); | |
462 alp = NULL; | |
463 } | |
464 } | |
465 if (alp != NULL) { | |
466 /* | |
467 * Return action list to kernel. | |
468 */ | |
469 res->mr_type.status = AUTOFS_ACTION; | |
470 res->mr_type.mount_result_type_u.list = alp; | |
471 } else { | |
472 /* | |
473 * No work to do left for the kernel | |
474 */ | |
475 res->mr_type.status = AUTOFS_DONE; | |
476 res->mr_type.mount_result_type_u.error = status; | |
477 } | |
478 | |
479 if (trace > 0) { | |
480 switch (res->mr_type.status) { | |
481 case AUTOFS_ACTION: | |
482 trace_prt(1, | |
483 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n", | |
484 status); | |
485 break; | |
486 case AUTOFS_DONE: | |
487 trace_prt(1, | |
488 "MOUNT REPLY : status=%d, AUTOFS_DONE\n", | |
489 status); | |
490 break; | |
491 default: | |
492 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n", | |
493 status); | |
494 } | |
495 } | |
496 | |
497 if (status && verbose) { | |
498 if (m->isdirect) { | |
499 /* direct mount */ | |
500 syslog(LOG_ERR, "mount of %s failed", m->path); | |
501 } else { | |
502 /* indirect mount */ | |
503 syslog(LOG_ERR, | |
504 "mount of %s/%s failed", m->path, m->name); | |
505 } | |
506 } | |
507 } | |
508 | |
509 static void | |
510 autofs_mount_1_free_r(struct autofs_mountres *res) | |
511 { | |
512 if (res->mr_type.status == AUTOFS_ACTION) { | |
513 if (trace > 2) | |
514 trace_prt(1, "freeing action list\n"); | |
515 free_action_list(res->mr_type.mount_result_type_u.list); | |
516 } | |
517 } | |
518 | |
519 /* | |
520 * Used for reporting messages from code shared with automount command. | |
521 * Formats message into a buffer and calls syslog. | |
522 * | |
523 * Print an error. Works like printf (fmt string and variable args) | |
524 * except that it will subsititute an error message for a "%m" string | |
525 * (like syslog). | |
526 */ | |
527 void | |
528 pr_msg(const char *fmt, ...) | |
529 { | |
530 va_list ap; | |
531 char fmtbuff[BUFSIZ], buff[BUFSIZ]; | |
532 const char *p1; | |
533 char *p2; | |
534 | |
535 p2 = fmtbuff; | |
536 fmt = gettext(fmt); | |
537 | |
538 for (p1 = fmt; *p1; p1++) { | |
539 if (*p1 == '%' && *(p1 + 1) == 'm') { | |
540 (void) strcpy(p2, strerror(errno)); | |
541 p2 += strlen(p2); | |
542 p1++; | |
543 } else { | |
544 *p2++ = *p1; | |
545 } | |
546 } | |
547 if (p2 > fmtbuff && *(p2-1) != '\n') | |
548 *p2++ = '\n'; | |
549 *p2 = '\0'; | |
550 | |
551 va_start(ap, fmt); | |
552 (void) vsprintf(buff, fmtbuff, ap); | |
553 va_end(ap); | |
554 syslog(LOG_ERR, buff); | |
555 } | |
556 | |
557 static void | |
558 free_action_list(action_list *alp) | |
559 { | |
560 action_list *p, *next = NULL; | |
561 struct mounta *mp; | |
562 | |
563 for (p = alp; p != NULL; p = next) { | |
564 switch (p->action.action) { | |
565 case AUTOFS_MOUNT_RQ: | |
566 mp = &(p->action.action_list_entry_u.mounta); | |
567 /* LINTED pointer alignment */ | |
568 if (mp->fstype) { | |
569 if (strcmp(mp->fstype, "autofs") == 0) { | |
570 free_autofs_args((autofs_args *) | |
571 mp->dataptr); | |
572 } else if (strncmp(mp->fstype, "nfs", 3) == 0) { | |
573 free_nfs_args((struct nfs_args *) | |
574 mp->dataptr); | |
575 } | |
576 } | |
577 mp->dataptr = NULL; | |
578 mp->datalen = 0; | |
579 free_mounta(mp); | |
580 break; | |
581 case AUTOFS_LINK_RQ: | |
582 syslog(LOG_ERR, | |
583 "non AUTOFS_MOUNT_RQ requests not implemented\n"); | |
584 break; | |
585 default: | |
586 syslog(LOG_ERR, | |
587 "non AUTOFS_MOUNT_RQ requests not implemented\n"); | |
588 break; | |
589 } | |
590 next = p->next; | |
591 free(p); | |
592 } | |
593 } | |
594 | |
595 static void | |
596 autofs_lookup_1_free_args(autofs_lookupargs *args) | |
597 { | |
598 if (args->map) | |
599 free(args->map); | |
600 if (args->path) | |
601 free(args->path); | |
602 if (args->name) | |
603 free(args->name); | |
604 if (args->subdir) | |
605 free(args->subdir); | |
606 if (args->opts) | |
607 free(args->opts); | |
608 } | |
609 | |
610 static void | |
611 autofs_unmount_1_free_args(umntrequest *args) | |
612 { | |
613 if (args->mntresource) | |
614 free(args->mntresource); | |
615 if (args->mntpnt) | |
616 free(args->mntpnt); | |
617 if (args->fstype) | |
618 free(args->fstype); | |
619 if (args->mntopts) | |
620 free(args->mntopts); | |
621 if (args->next) | |
622 autofs_unmount_1_free_args(args->next); | |
623 } | |
624 | |
625 static void | |
626 autofs_setdoor(int did) | |
627 { | |
628 | |
629 if (did < 0) { | |
630 did = 0; | |
631 } | |
632 | |
633 (void) _autofssys(AUTOFS_SETDOOR, &did); | |
634 } | |
635 | |
636 void * | |
637 autofs_get_buffer(size_t size) | |
638 { | |
639 autofs_tsd_t *tsd = NULL; | |
640 | |
641 /* | |
642 * Make sure the buffer size is aligned | |
643 */ | |
644 (void) thr_getspecific(s_thr_key, (void **)&tsd); | |
645 if (tsd == NULL) { | |
646 tsd = (autofs_tsd_t *)malloc(sizeof (autofs_tsd_t)); | |
647 if (tsd == NULL) { | |
648 return (NULL); | |
649 } | |
650 tsd->atsd_buf = malloc(size); | |
651 if (tsd->atsd_buf != NULL) | |
652 tsd->atsd_len = size; | |
653 else | |
654 tsd->atsd_len = 0; | |
655 (void) thr_setspecific(s_thr_key, tsd); | |
656 } else { | |
657 if (tsd->atsd_buf && (tsd->atsd_len < size)) { | |
658 free(tsd->atsd_buf); | |
659 tsd->atsd_buf = malloc(size); | |
660 if (tsd->atsd_buf != NULL) | |
661 tsd->atsd_len = size; | |
662 else { | |
663 tsd->atsd_len = 0; | |
664 } | |
665 } | |
666 } | |
667 if (tsd->atsd_buf) { | |
668 bzero(tsd->atsd_buf, size); | |
669 return (tsd->atsd_buf); | |
670 } else { | |
671 syslog(LOG_ERR, | |
672 gettext("Can't Allocate tsd buffer, size %d"), size); | |
673 return (NULL); | |
674 } | |
675 } | |
676 | |
677 /* | |
678 * Each request will automatically spawn a new thread with this | |
679 * as its entry point. | |
680 */ | |
681 /* ARGUSED */ | |
682 static void | |
683 autofs_doorfunc( | |
684 void *cookie, | |
685 char *argp, | |
686 size_t arg_size, | |
687 door_desc_t *dp, | |
688 uint_t n_desc) | |
689 { | |
690 char *res; | |
691 int res_size; | |
692 int which; | |
693 int error = 0; | |
694 int srsz = 0; | |
695 autofs_lookupargs *xdrargs; | |
696 autofs_lookupres lookup_res; | |
697 autofs_rddirargs *rddir_args; | |
698 autofs_rddirres rddir_res; | |
699 autofs_mountres mount_res; | |
700 umntrequest *umnt_args; | |
701 umntres umount_res; | |
702 autofs_door_res_t *door_res; | |
703 autofs_door_res_t failed_res; | |
704 | |
705 if (arg_size < sizeof (autofs_door_args_t)) { | |
706 failed_res.res_status = EINVAL; | |
707 error = door_return((char *)&failed_res, | |
708 sizeof (autofs_door_res_t), NULL, 0); | |
709 /* | |
710 * If we got here the door_return() failed. | |
711 */ | |
712 syslog(LOG_ERR, "Bad argument, door_return failure %d", error); | |
713 return; | |
714 } | |
715 | |
716 timenow = time((time_t *)NULL); | |
717 | |
718 which = ((autofs_door_args_t *)argp)->cmd; | |
719 switch (which) { | |
720 case AUTOFS_LOOKUP: | |
721 if (error = decode_args(xdr_autofs_lookupargs, | |
722 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs, | |
723 sizeof (autofs_lookupargs))) { | |
724 syslog(LOG_ERR, | |
725 "error allocating lookup arguments buffer"); | |
726 failed_res.res_status = error; | |
727 failed_res.xdr_len = 0; | |
728 res = (caddr_t)&failed_res; | |
729 res_size = 0; | |
730 break; | |
731 } | |
732 bzero(&lookup_res, sizeof (autofs_lookupres)); | |
733 | |
734 autofs_lookup_1_r(xdrargs, &lookup_res); | |
735 | |
736 autofs_lookup_1_free_args(xdrargs); | |
737 free(xdrargs); | |
738 | |
739 if (!encode_res(xdr_autofs_lookupres, &door_res, | |
740 (caddr_t)&lookup_res, &res_size)) { | |
741 syslog(LOG_ERR, | |
742 "error allocating lookup results buffer"); | |
743 failed_res.res_status = EINVAL; | |
744 failed_res.xdr_len = 0; | |
745 res = (caddr_t)&failed_res; | |
746 } else { | |
747 door_res->res_status = 0; | |
748 res = (caddr_t)door_res; | |
749 } | |
750 break; | |
751 | |
752 case AUTOFS_MNTINFO: | |
753 if (error = decode_args(xdr_autofs_lookupargs, | |
754 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs, | |
755 sizeof (autofs_lookupargs))) { | |
756 syslog(LOG_ERR, | |
757 "error allocating lookup arguments buffer"); | |
758 failed_res.res_status = error; | |
759 failed_res.xdr_len = 0; | |
760 res = (caddr_t)&failed_res; | |
761 res_size = 0; | |
762 break; | |
763 } | |
764 | |
765 autofs_mntinfo_1_r((autofs_lookupargs *)xdrargs, &mount_res); | |
766 | |
767 autofs_lookup_1_free_args(xdrargs); | |
768 free(xdrargs); | |
769 | |
770 /* | |
771 * Only reason we would get a NULL res is because | |
772 * we could not allocate a results buffer. Use | |
773 * a local one to return the error EAGAIN as has | |
774 * always been done when memory allocations fail. | |
775 */ | |
776 if (!encode_res(xdr_autofs_mountres, &door_res, | |
777 (caddr_t)&mount_res, &res_size)) { | |
778 syslog(LOG_ERR, | |
779 "error allocating mount results buffer"); | |
780 failed_res.res_status = EAGAIN; | |
781 failed_res.xdr_len = 0; | |
782 res = (caddr_t)&failed_res; | |
783 } else { | |
784 door_res->res_status = 0; | |
785 res = (caddr_t)door_res; | |
786 } | |
787 autofs_mount_1_free_r(&mount_res); | |
788 break; | |
789 | |
790 case AUTOFS_UNMOUNT: | |
791 if (error = decode_args(xdr_umntrequest, | |
792 (autofs_door_args_t *)argp, | |
793 (caddr_t *)&umnt_args, sizeof (umntrequest))) { | |
794 syslog(LOG_ERR, | |
795 "error allocating unmount argument buffer"); | |
796 failed_res.res_status = error; | |
797 failed_res.xdr_len = 0; | |
798 res = (caddr_t)&failed_res; | |
799 res_size = sizeof (autofs_door_res_t); | |
800 break; | |
801 } | |
802 | |
803 autofs_unmount_1_r(umnt_args, &umount_res); | |
804 | |
805 error = umount_res.status; | |
806 | |
807 autofs_unmount_1_free_args(umnt_args); | |
808 free(umnt_args); | |
809 | |
810 if (!encode_res(xdr_umntres, &door_res, (caddr_t)&umount_res, | |
811 &res_size)) { | |
812 syslog(LOG_ERR, | |
813 "error allocating unmount results buffer"); | |
814 failed_res.res_status = EINVAL; | |
815 failed_res.xdr_len = 0; | |
816 res = (caddr_t)&failed_res; | |
817 res_size = sizeof (autofs_door_res_t); | |
818 } else { | |
819 door_res->res_status = 0; | |
820 res = (caddr_t)door_res; | |
821 } | |
822 break; | |
823 | |
824 case AUTOFS_READDIR: | |
825 if (error = decode_args(xdr_autofs_rddirargs, | |
826 (autofs_door_args_t *)argp, | |
827 (caddr_t *)&rddir_args, | |
828 sizeof (autofs_rddirargs))) { | |
829 syslog(LOG_ERR, | |
830 "error allocating readdir argument buffer"); | |
831 failed_res.res_status = error; | |
832 failed_res.xdr_len = 0; | |
833 res = (caddr_t)&failed_res; | |
834 res_size = sizeof (autofs_door_res_t); | |
835 break; | |
836 } | |
837 | |
838 autofs_readdir_1_r(rddir_args, &rddir_res); | |
839 | |
840 free(rddir_args->rda_map); | |
841 free(rddir_args); | |
842 | |
843 if (!encode_res(xdr_autofs_rddirres, &door_res, | |
844 (caddr_t)&rddir_res, &res_size)) { | |
845 syslog(LOG_ERR, | |
846 "error allocating readdir results buffer"); | |
847 failed_res.res_status = ENOMEM; | |
848 failed_res.xdr_len = 0; | |
849 res = (caddr_t)&failed_res; | |
850 res_size = sizeof (autofs_door_res_t); | |
851 } else { | |
852 door_res->res_status = 0; | |
853 res = (caddr_t)door_res; | |
854 } | |
855 autofs_readdir_1_free_r(&rddir_res); | |
856 break; | |
857 #ifdef MALLOC_DEBUG | |
858 case AUTOFS_DUMP_DEBUG: | |
859 check_leaks("/var/tmp/automountd.leak"); | |
860 error = door_return(NULL, 0, NULL, 0); | |
861 /* | |
862 * If we got here, door_return() failed | |
863 */ | |
864 syslog(LOG_ERR, "dump debug door_return failure %d", | |
865 error); | |
866 return; | |
867 #endif | |
868 case NULLPROC: | |
869 res = NULL; | |
870 res_size = 0; | |
871 break; | |
872 default: | |
873 failed_res.res_status = EINVAL; | |
874 res = (char *)&failed_res; | |
875 res_size = sizeof (autofs_door_res_t); | |
876 break; | |
877 } | |
878 | |
879 srsz = res_size; | |
880 errno = 0; | |
881 error = door_return(res, res_size, NULL, 0); | |
882 | |
883 if (errno == E2BIG) { | |
884 /* | |
885 * Failed due to encoded results being bigger than the | |
886 * kernel expected bufsize. Passing actual results size | |
887 * back down to kernel. | |
888 */ | |
889 failed_res.res_status = EOVERFLOW; | |
890 failed_res.xdr_len = srsz; | |
891 res = (caddr_t)&failed_res; | |
892 res_size = sizeof (autofs_door_res_t); | |
893 } else { | |
894 syslog(LOG_ERR, "door_return failed %d, buffer %p, " | |
895 "buffer size %d", error, (void *)res, res_size); | |
896 res = NULL; | |
897 res_size = 0; | |
898 } | |
899 (void) door_return(res, res_size, NULL, 0); | |
900 /* NOTREACHED */ | |
901 } | |
902 | |
903 static int | |
904 start_autofs_svcs(void) | |
905 { | |
906 int doorfd; | |
907 #ifdef DEBUG | |
908 int dfd; | |
909 #endif | |
910 | |
911 if ((doorfd = door_create(autofs_doorfunc, NULL, | |
912 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { | |
913 syslog(LOG_ERR, gettext("Unable to create door\n")); | |
914 return (1); | |
915 } | |
916 | |
917 #ifdef DEBUG | |
918 /* | |
919 * Create a file system path for the door | |
920 */ | |
921 if ((dfd = open(AUTOFS_DOOR, O_RDWR|O_CREAT|O_TRUNC, | |
922 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { | |
923 syslog(LOG_ERR, "Unable to open %s: %m\n", AUTOFS_DOOR); | |
924 (void) close(doorfd); | |
925 return (1); | |
926 } | |
927 | |
928 /* | |
929 * stale associations clean up | |
930 */ | |
931 (void) fdetach(AUTOFS_DOOR); | |
932 | |
933 /* | |
934 * Register in the namespace to the kernel to door_ki_open. | |
935 */ | |
936 if (fattach(doorfd, AUTOFS_DOOR) == -1) { | |
937 syslog(LOG_ERR, "Unable to fattach door %m\n", AUTOFS_DOOR); | |
938 (void) close(dfd); | |
939 (void) close(doorfd); | |
940 return (1); | |
941 } | |
942 #endif /* DEBUG */ | |
943 | |
944 /* | |
945 * Pass door name to kernel for door_ki_open | |
946 */ | |
947 autofs_setdoor(doorfd); | |
948 | |
949 (void) thr_keycreate(&s_thr_key, NULL); | |
950 | |
951 /* | |
952 * Wait for incoming calls | |
953 */ | |
954 /*CONSTCOND*/ | |
955 while (1) | |
956 (void) pause(); | |
957 | |
958 /* NOTREACHED */ | |
959 syslog(LOG_ERR, gettext("Door server exited")); | |
960 return (10); | |
961 } | |
962 | |
963 static int | |
964 decode_args( | |
965 xdrproc_t xdrfunc, | |
966 autofs_door_args_t *argp, | |
967 caddr_t *xdrargs, | |
968 int size) | |
969 { | |
970 XDR xdrs; | |
971 | |
972 caddr_t tmpargs = (caddr_t)&((autofs_door_args_t *)argp)->xdr_arg; | |
973 size_t arg_size = ((autofs_door_args_t *)argp)->xdr_len; | |
974 | |
975 xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE); | |
976 | |
977 *xdrargs = malloc(size); | |
978 if (*xdrargs == NULL) { | |
979 syslog(LOG_ERR, "error allocating arguments buffer"); | |
980 return (ENOMEM); | |
981 } | |
982 | |
983 bzero(*xdrargs, size); | |
984 | |
985 if (!(*xdrfunc)(&xdrs, *xdrargs)) { | |
986 free(*xdrargs); | |
987 *xdrargs = NULL; | |
988 syslog(LOG_ERR, "error decoding arguments"); | |
989 return (EINVAL); | |
990 } | |
991 | |
992 return (0); | |
993 } | |
994 | |
995 | |
996 static bool_t | |
997 encode_res( | |
998 xdrproc_t xdrfunc, | |
999 autofs_door_res_t **results, | |
1000 caddr_t resp, | |
1001 int *size) | |
1002 { | |
1003 XDR xdrs; | |
1004 | |
1005 *size = xdr_sizeof((*xdrfunc), resp); | |
1006 *results = autofs_get_buffer( | |
1007 sizeof (autofs_door_res_t) + *size); | |
1008 if (*results == NULL) { | |
1009 (*results)->res_status = ENOMEM; | |
1010 return (FALSE); | |
1011 } | |
1012 (*results)->xdr_len = *size; | |
1013 *size = sizeof (autofs_door_res_t) + (*results)->xdr_len; | |
1014 xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res), | |
1015 (*results)->xdr_len, XDR_ENCODE); | |
1016 if (!(*xdrfunc)(&xdrs, resp)) { | |
1017 (*results)->res_status = EINVAL; | |
1018 syslog(LOG_ERR, "error encoding results"); | |
1019 return (FALSE); | |
1020 } | |
1021 (*results)->res_status = 0; | |
1022 return (TRUE); | |
1023 } | |
1024 | |
1025 static void | |
1026 automountd_wait_for_cleanup(pid_t pid) | |
1027 { | |
1028 int status; | |
1029 int child_exitval; | |
1030 | |
1031 /* | |
1032 * Wait for the main automountd process to exit so we cleanup | |
1033 */ | |
1034 (void) waitpid(pid, &status, 0); | |
1035 | |
1036 child_exitval = WEXITSTATUS(status); | |
1037 | |
1038 /* | |
1039 * Shutdown the door server for mounting and unmounting | |
1040 * filesystems | |
1041 */ | |
1042 if (door_revoke(did_fork_exec) == -1) { | |
1043 syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_fork_exec); | |
1044 } | |
1045 if (door_revoke(did_exec_map) == -1) { | |
1046 syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_exec_map); | |
1047 } | |
1048 exit(child_exitval); | |
1049 } |