MFC r1.27:
[dragonfly.git] / contrib / amd / amd / amd.c
blobb25c0416fd5108f1c4cc229fe3034059cf8fb5c1
1 /*
2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1989 Jan-Simon Pendry
4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1989 The Regents of the University of California.
6 * All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 * %W% (Berkeley) %G%
41 * $Id: amd.c,v 1.6 1999/09/30 21:01:29 ezk Exp $
42 * $FreeBSD: src/contrib/amd/amd/amd.c,v 1.6.2.1 2000/09/20 02:17:04 jkh Exp $
43 * $DragonFly: src/contrib/amd/amd/amd.c,v 1.2 2003/06/17 04:23:56 dillon Exp $
48 * Automounter
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif /* HAVE_CONFIG_H */
54 #include <am_defs.h>
55 #include <amd.h>
57 struct amu_global_options gopt; /* where global options are stored */
59 char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */
60 char *hostdomain = "unknown.domain";
61 char hostd[2 * MAXHOSTNAMELEN + 1]; /* Host+domain */
62 char *endian = ARCH_ENDIAN; /* Big or Little endian */
63 char *cpu = HOST_CPU; /* CPU type */
64 char *PrimNetName; /* name of primary network */
65 char *PrimNetNum; /* number of primary network */
67 int immediate_abort; /* Should close-down unmounts be retried */
68 int orig_umask = 022;
69 int select_intr_valid;
71 jmp_buf select_intr;
72 struct amd_stats amd_stats; /* Server statistics */
73 struct in_addr myipaddr; /* (An) IP address of this host */
74 time_t do_mapc_reload = 0; /* mapc_reload() call required? */
76 #ifdef HAVE_SIGACTION
77 sigset_t masked_sigs;
78 #endif /* HAVE_SIGACTION */
82 * Signal handler:
83 * SIGINT - tells amd to do a full shutdown, including unmounting all
84 * filesystem.
85 * SIGTERM - tells amd to shutdown now. Just unmounts the automount nodes.
87 static RETSIGTYPE
88 sigterm(int sig)
90 #ifdef REINSTALL_SIGNAL_HANDLER
91 signal(sig, sigterm);
92 #endif /* REINSTALL_SIGNAL_HANDLER */
94 switch (sig) {
95 case SIGINT:
96 immediate_abort = 15;
97 break;
99 case SIGTERM:
100 immediate_abort = -1;
101 /* fall through... */
103 default:
104 plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
105 break;
107 if (select_intr_valid)
108 longjmp(select_intr, sig);
113 * Hook for cache reload.
114 * When a SIGHUP arrives it schedules a call to mapc_reload
116 static RETSIGTYPE
117 sighup(int sig)
119 #ifdef REINSTALL_SIGNAL_HANDLER
120 signal(sig, sighup);
121 #endif /* REINSTALL_SIGNAL_HANDLER */
123 #ifdef DEBUG
124 if (sig != SIGHUP)
125 dlog("spurious call to sighup");
126 #endif /* DEBUG */
128 * Force a reload by zero'ing the timer
130 if (amd_state == Run)
131 do_mapc_reload = 0;
135 static RETSIGTYPE
136 parent_exit(int sig)
138 exit(0);
142 static int
143 daemon_mode(void)
145 int bgpid;
147 #ifdef HAVE_SIGACTION
148 struct sigaction sa, osa;
150 sa.sa_handler = parent_exit;
151 sa.sa_flags = 0;
152 sigemptyset(&(sa.sa_mask));
153 sigaddset(&(sa.sa_mask), SIGQUIT);
154 sigaction(SIGQUIT, &sa, &osa);
155 #else /* not HAVE_SIGACTION */
156 signal(SIGQUIT, parent_exit);
157 #endif /* not HAVE_SIGACTION */
159 bgpid = background();
161 if (bgpid != 0) {
163 * Now wait for the automount points to
164 * complete.
166 for (;;)
167 pause();
168 /* should never reach here */
170 #ifdef HAVE_SIGACTION
171 sigaction(SIGQUIT, &osa, NULL);
172 #else /* not HAVE_SIGACTION */
173 signal(SIGQUIT, SIG_DFL);
174 #endif /* not HAVE_SIGACTION */
177 * Record our pid to make it easier to kill the correct amd.
179 if (gopt.flags & CFM_PRINT_PID) {
180 if (STREQ(gopt.pid_file, "/dev/stdout")) {
181 printf("%ld\n", (long) am_mypid);
182 fflush(stdout);
183 /* do not fclose stdout */
184 } else {
185 FILE *f;
186 mode_t prev_umask = umask(0022); /* set secure temporary umask */
188 f = fopen(gopt.pid_file, "w");
189 if (f) {
190 fprintf(f, "%ld\n", (long) am_mypid);
191 (void) fclose(f);
192 } else {
193 fprintf(stderr, "cannot open %s (errno=%d)\n", gopt.pid_file, errno);
195 umask(prev_umask); /* restore umask */
200 * Pretend we are in the foreground again
202 foreground = 1;
205 * Dissociate from the controlling terminal
207 amu_release_controlling_tty();
209 return getppid();
214 * Initialize global options structure.
216 static void
217 init_global_options(void)
219 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
220 static struct utsname un;
221 #endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
223 memset(&gopt, 0, sizeof(struct amu_global_options));
225 /* name of current architecture */
226 gopt.arch = HOST_ARCH;
228 /* automounter temp dir */
229 gopt.auto_dir = "/.amd_mnt";
231 /* cluster name */
232 gopt.cluster = NULL;
235 * kernel architecture: this you must get from uname() if possible.
237 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
238 if (uname(&un) >= 0)
239 gopt.karch = un.machine;
240 else
241 #endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
242 gopt.karch = HOST_ARCH;
244 /* amd log file */
245 gopt.logfile = NULL;
247 /* operating system name */
248 gopt.op_sys = HOST_OS_NAME;
250 /* OS version */
251 gopt.op_sys_ver = HOST_OS_VERSION;
253 /* full OS name and version */
254 gopt.op_sys_full = HOST_OS;
256 /* OS version */
257 gopt.op_sys_vendor = HOST_VENDOR;
259 /* pid file */
260 gopt.pid_file = "/dev/stdout";
262 /* local domain */
263 gopt.sub_domain = NULL;
265 /* NFS retransmit counter */
266 gopt.amfs_auto_retrans = -1;
268 /* NFS retry interval */
269 gopt.amfs_auto_timeo = -1;
271 /* cache duration */
272 gopt.am_timeo = AM_TTL;
274 /* dismount interval */
275 gopt.am_timeo_w = AM_TTL_W;
278 * various CFM_* flags.
279 * by default, only the "plock" option is on (if available).
281 gopt.flags = CFM_PROCESS_LOCK;
283 #ifdef HAVE_MAP_HESIOD
284 /* Hesiod rhs zone */
285 gopt.hesiod_base = "automount";
286 #endif /* HAVE_MAP_HESIOD */
288 #ifdef HAVE_MAP_LDAP
289 /* LDAP base */
290 gopt.ldap_base = NULL;
292 /* LDAP host ports */
293 gopt.ldap_hostports = NULL;
295 /* LDAP cache */
296 gopt.ldap_cache_seconds = 0;
297 gopt.ldap_cache_maxmem = 131072;
298 #endif /* HAVE_MAP_LDAP */
300 #ifdef HAVE_MAP_NIS
301 /* YP domain name */
302 gopt.nis_domain = NULL;
303 #endif /* HAVE_MAP_NIS */
308 main(int argc, char *argv[])
310 char *domdot, *verstr;
311 int ppid = 0;
312 int error;
313 char *progname = NULL; /* "amd" */
314 char hostname[MAXHOSTNAMELEN + 1] = "localhost"; /* Hostname */
315 #ifdef HAVE_SIGACTION
316 struct sigaction sa;
317 #endif /* HAVE_SIGACTION */
320 * Make sure some built-in assumptions are true before we start
322 assert(sizeof(nfscookie) >= sizeof(u_int));
323 assert(sizeof(int) >= 4);
326 * Set processing status.
328 amd_state = Start;
331 * Determine program name
333 if (argv[0]) {
334 progname = strrchr(argv[0], '/');
335 if (progname && progname[1])
336 progname++;
337 else
338 progname = argv[0];
340 if (!progname)
341 progname = "amd";
342 am_set_progname(progname);
345 * Initialize process id. This is kept
346 * cached since it is used for generating
347 * and using file handles.
349 am_set_mypid();
352 * Get local machine name
354 if (gethostname(hostname, sizeof(hostname)) < 0) {
355 plog(XLOG_FATAL, "gethostname: %m");
356 going_down(1);
358 hostname[sizeof(hostname) - 1] = '\0';
361 * Check it makes sense
363 if (!*hostname) {
364 plog(XLOG_FATAL, "host name is not set");
365 going_down(1);
368 #ifdef DEBUG
369 /* initialize debugging flags (Register AMQ, Enter daemon mode) */
370 debug_flags = D_AMQ | D_DAEMON;
371 #endif /* DEBUG */
374 * Initialize global options structure.
376 init_global_options();
379 * Partially initialize hostd[]. This
380 * is completed in get_args().
382 if ((domdot = strchr(hostname, '.'))) {
384 * Hostname already contains domainname.
385 * Split out hostname and domainname
386 * components
388 *domdot++ = '\0';
389 hostdomain = domdot;
391 strcpy(hostd, hostname);
392 am_set_hostname(hostname);
395 * Trap interrupts for shutdowns.
397 #ifdef HAVE_SIGACTION
398 sa.sa_handler = sigterm;
399 sa.sa_flags = 0;
400 sigemptyset(&(sa.sa_mask));
401 sigaddset(&(sa.sa_mask), SIGINT);
402 sigaddset(&(sa.sa_mask), SIGTERM);
403 sigaction(SIGINT, &sa, NULL);
404 sigaction(SIGTERM, &sa, NULL);
405 #else /* not HAVE_SIGACTION */
406 (void) signal(SIGINT, sigterm);
407 #endif /* not HAVE_SIGACTION */
410 * Trap Terminate so that we can shutdown gracefully (some chance)
412 #ifdef HAVE_SIGACTION
413 sa.sa_handler = sigterm;
414 sa.sa_flags = 0;
415 sigemptyset(&(sa.sa_mask));
416 sigaddset(&(sa.sa_mask), SIGTERM);
417 sigaction(SIGTERM, &sa, NULL);
418 #else /* not HAVE_SIGACTION */
419 (void) signal(SIGTERM, sigterm);
420 #endif /* not HAVE_SIGACTION */
423 * Hangups tell us to reload the cache
425 #ifdef HAVE_SIGACTION
426 sa.sa_handler = sighup;
427 sa.sa_flags = 0;
428 sigemptyset(&(sa.sa_mask));
429 sigaddset(&(sa.sa_mask), SIGHUP);
430 sigaction(SIGHUP, &sa, NULL);
431 #else /* not HAVE_SIGACTION */
432 (void) signal(SIGHUP, sighup);
433 #endif /* not HAVE_SIGACTION */
436 * Trap Death-of-a-child. These allow us to
437 * pick up the exit status of backgrounded mounts.
438 * See "sched.c".
440 #ifdef HAVE_SIGACTION
441 sa.sa_handler = sigchld;
442 sa.sa_flags = 0;
443 sigemptyset(&(sa.sa_mask));
444 sigaddset(&(sa.sa_mask), SIGCHLD);
445 sigaction(SIGCHLD, &sa, NULL);
448 * construct global "masked_sigs" used in nfs_start.c
450 sigemptyset(&masked_sigs);
451 sigaddset(&masked_sigs, SIGHUP);
452 sigaddset(&masked_sigs, SIGCHLD);
453 sigaddset(&masked_sigs, SIGTERM);
454 sigaddset(&masked_sigs, SIGINT);
455 #else /* not HAVE_SIGACTION */
456 (void) signal(SIGCHLD, sigchld);
457 #endif /* not HAVE_SIGACTION */
460 * Fix-up any umask problems. Most systems default
461 * to 002 which is not too convenient for our purposes
463 orig_umask = umask(0);
466 * Figure out primary network name
468 getwire(&PrimNetName, &PrimNetNum);
471 * Determine command-line arguments
473 get_args(argc, argv);
476 * Log version information.
478 verstr = strtok(get_version_string(), "\n");
479 plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:");
480 while (verstr) {
481 plog(XLOG_INFO, verstr);
482 verstr = strtok(NULL, "\n");
486 * Get our own IP address so that we
487 * can mount the automounter.
489 amu_get_myaddress(&myipaddr);
490 plog(XLOG_INFO, "My ip addr is %s", inet_ntoa(myipaddr));
492 /* avoid hanging on other NFS servers if started elsewhere */
493 if (chdir("/") < 0)
494 plog(XLOG_INFO, "cannot chdir to /: %m");
497 * Now check we are root.
499 if (geteuid() != 0) {
500 plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %ld)", (long) geteuid());
501 going_down(1);
505 * Lock process text and data segment in memory.
507 #ifdef HAVE_PLOCK
508 if (gopt.flags & CFM_PROCESS_LOCK) {
509 # ifdef _AIX
511 * On AIX you must lower the stack size using ulimit() before calling
512 * plock. Otherwise plock will reserve a lot of memory space based on
513 * your maximum stack size limit. Since it is not easily possible to
514 * tell what should the limit be, I print a warning before calling
515 * plock(). See the manual pages for ulimit(1,3,4) on your AIX system.
517 plog(XLOG_WARNING, "AIX: may need to lower stack size using ulimit(3) before calling plock");
518 # endif /* _AIX */
519 if (plock(PROCLOCK) != 0) {
520 plog(XLOG_WARNING, "Couldn't lock process text and data segment in memory: %m");
521 } else {
522 plog(XLOG_INFO, "Locked process text and data segment in memory");
525 #endif /* HAVE_PLOCK */
527 #ifdef HAVE_MAP_NIS
529 * If the domain was specified then bind it here
530 * to circumvent any default bindings that may
531 * be done in the C library.
533 if (gopt.nis_domain && yp_bind(gopt.nis_domain)) {
534 plog(XLOG_FATAL, "Can't bind to NIS domain \"%s\"", gopt.nis_domain);
535 going_down(1);
537 #endif /* HAVE_MAP_NIS */
539 #ifdef DEBUG
540 amuDebug(D_DAEMON)
541 #endif /* DEBUG */
542 ppid = daemon_mode();
544 sprintf(pid_fsname, "%s:(pid%ld)", am_get_hostname(), (long) am_mypid);
546 do_mapc_reload = clocktime() + ONE_HOUR;
549 * Register automounter with system.
551 error = mount_automounter(ppid);
552 if (error && ppid)
553 kill(ppid, SIGALRM);
554 going_down(error);
556 abort();
557 return 1; /* should never get here */