Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / amd / amd / amd.c
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.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
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.
26  *
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.
38  *
39  *      %W% (Berkeley) %G%
40  *
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  *
44  */
45
46 /*
47  * Automounter
48  */
49
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <amd.h>
55
56 struct amu_global_options gopt; /* where global options are stored */
57
58 char pid_fsname[16 + MAXHOSTNAMELEN];   /* "kiska.southseas.nz:(pid%d)" */
59 char *hostdomain = "unknown.domain";
60 char hostd[2 * MAXHOSTNAMELEN + 1]; /* Host+domain */
61 char *endian = ARCH_ENDIAN;     /* Big or Little endian */
62 char *cpu = HOST_CPU;           /* CPU type */
63 char *PrimNetName;              /* name of primary network */
64 char *PrimNetNum;               /* number of primary network */
65
66 int immediate_abort;            /* Should close-down unmounts be retried */
67 int orig_umask = 022;
68 int select_intr_valid;
69
70 jmp_buf select_intr;
71 struct amd_stats amd_stats;     /* Server statistics */
72 struct in_addr myipaddr;        /* (An) IP address of this host */
73 time_t do_mapc_reload = 0;      /* mapc_reload() call required? */
74
75 #ifdef HAVE_SIGACTION
76 sigset_t masked_sigs;
77 #endif /* HAVE_SIGACTION */
78
79
80 /*
81  * Signal handler:
82  * SIGINT - tells amd to do a full shutdown, including unmounting all
83  *       filesystem.
84  * SIGTERM - tells amd to shutdown now.  Just unmounts the automount nodes.
85  */
86 static RETSIGTYPE
87 sigterm(int sig)
88 {
89 #ifdef REINSTALL_SIGNAL_HANDLER
90   signal(sig, sigterm);
91 #endif /* REINSTALL_SIGNAL_HANDLER */
92
93   switch (sig) {
94   case SIGINT:
95     immediate_abort = 15;
96     break;
97
98   case SIGTERM:
99     immediate_abort = -1;
100     /* fall through... */
101
102   default:
103     plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
104     break;
105   }
106   if (select_intr_valid)
107     longjmp(select_intr, sig);
108 }
109
110
111 /*
112  * Hook for cache reload.
113  * When a SIGHUP arrives it schedules a call to mapc_reload
114  */
115 static RETSIGTYPE
116 sighup(int sig)
117 {
118 #ifdef REINSTALL_SIGNAL_HANDLER
119   signal(sig, sighup);
120 #endif /* REINSTALL_SIGNAL_HANDLER */
121
122 #ifdef DEBUG
123   if (sig != SIGHUP)
124     dlog("spurious call to sighup");
125 #endif /* DEBUG */
126   /*
127    * Force a reload by zero'ing the timer
128    */
129   if (amd_state == Run)
130     do_mapc_reload = 0;
131 }
132
133
134 static RETSIGTYPE
135 parent_exit(int sig)
136 {
137   exit(0);
138 }
139
140
141 static int
142 daemon_mode(void)
143 {
144   int bgpid;
145
146 #ifdef HAVE_SIGACTION
147   struct sigaction sa, osa;
148
149   sa.sa_handler = parent_exit;
150   sa.sa_flags = 0;
151   sigemptyset(&(sa.sa_mask));
152   sigaddset(&(sa.sa_mask), SIGQUIT);
153   sigaction(SIGQUIT, &sa, &osa);
154 #else /* not HAVE_SIGACTION */
155   signal(SIGQUIT, parent_exit);
156 #endif /* not HAVE_SIGACTION */
157
158   bgpid = background();
159
160   if (bgpid != 0) {
161     /*
162      * Now wait for the automount points to
163      * complete.
164      */
165     for (;;)
166       pause();
167     /* should never reach here */
168   }
169 #ifdef HAVE_SIGACTION
170   sigaction(SIGQUIT, &osa, NULL);
171 #else /* not HAVE_SIGACTION */
172   signal(SIGQUIT, SIG_DFL);
173 #endif /* not HAVE_SIGACTION */
174
175   /*
176    * Record our pid to make it easier to kill the correct amd.
177    */
178   if (gopt.flags & CFM_PRINT_PID) {
179     if (STREQ(gopt.pid_file, "/dev/stdout")) {
180       printf("%ld\n", (long) am_mypid);
181       fflush(stdout);
182       /* do not fclose stdout */
183     } else {
184       FILE *f;
185       mode_t prev_umask = umask(0022); /* set secure temporary umask */
186
187       f = fopen(gopt.pid_file, "w");
188       if (f) {
189         fprintf(f, "%ld\n", (long) am_mypid);
190         (void) fclose(f);
191       } else {
192         fprintf(stderr, "cannot open %s (errno=%d)\n", gopt.pid_file, errno);
193       }
194       umask(prev_umask);        /* restore umask */
195     }
196   }
197
198   /*
199    * Pretend we are in the foreground again
200    */
201   foreground = 1;
202
203   /*
204    * Dissociate from the controlling terminal
205    */
206   amu_release_controlling_tty();
207
208   return getppid();
209 }
210
211
212 /*
213  * Initialize global options structure.
214  */
215 static void
216 init_global_options(void)
217 {
218 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
219   static struct utsname un;
220 #endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
221
222   memset(&gopt, 0, sizeof(struct amu_global_options));
223
224   /* name of current architecture */
225   gopt.arch = HOST_ARCH;
226
227   /* automounter temp dir */
228   gopt.auto_dir = "/.amd_mnt";
229
230   /* cluster name */
231   gopt.cluster = NULL;
232
233   /*
234    * kernel architecture: this you must get from uname() if possible.
235    */
236 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
237   if (uname(&un) >= 0)
238     gopt.karch = un.machine;
239   else
240 #endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
241     gopt.karch = HOST_ARCH;
242
243   /* amd log file */
244   gopt.logfile = NULL;
245
246   /* operating system name */
247   gopt.op_sys = HOST_OS_NAME;
248
249   /* OS version */
250   gopt.op_sys_ver = HOST_OS_VERSION;
251
252   /* full OS name and version */
253   gopt.op_sys_full = HOST_OS;
254
255   /* OS version */
256   gopt.op_sys_vendor = HOST_VENDOR;
257
258   /* pid file */
259   gopt.pid_file = "/dev/stdout";
260
261   /* local domain */
262   gopt.sub_domain = NULL;
263
264   /* NFS retransmit counter */
265   gopt.amfs_auto_retrans = -1;
266
267   /* NFS retry interval */
268   gopt.amfs_auto_timeo = -1;
269
270   /* cache duration */
271   gopt.am_timeo = AM_TTL;
272
273   /* dismount interval */
274   gopt.am_timeo_w = AM_TTL_W;
275
276   /*
277    * various CFM_* flags.
278    * by default, only the "plock" option is on (if available).
279    */
280   gopt.flags = CFM_PROCESS_LOCK;
281
282 #ifdef HAVE_MAP_HESIOD
283   /* Hesiod rhs zone */
284   gopt.hesiod_base = "automount";
285 #endif /* HAVE_MAP_HESIOD */
286
287 #ifdef HAVE_MAP_LDAP
288   /* LDAP base */
289   gopt.ldap_base = NULL;
290
291   /* LDAP host ports */
292   gopt.ldap_hostports = NULL;
293
294   /* LDAP cache */
295   gopt.ldap_cache_seconds = 0;
296   gopt.ldap_cache_maxmem = 131072;
297 #endif /* HAVE_MAP_LDAP */
298
299 #ifdef HAVE_MAP_NIS
300   /* YP domain name */
301   gopt.nis_domain = NULL;
302 #endif /* HAVE_MAP_NIS */
303 }
304
305
306 int
307 main(int argc, char *argv[])
308 {
309   char *domdot, *verstr;
310   int ppid = 0;
311   int error;
312   char *progname = NULL;                /* "amd" */
313   char hostname[MAXHOSTNAMELEN + 1] = "localhost"; /* Hostname */
314 #ifdef HAVE_SIGACTION
315   struct sigaction sa;
316 #endif /* HAVE_SIGACTION */
317
318   /*
319    * Make sure some built-in assumptions are true before we start
320    */
321   assert(sizeof(nfscookie) >= sizeof(u_int));
322   assert(sizeof(int) >= 4);
323
324   /*
325    * Set processing status.
326    */
327   amd_state = Start;
328
329   /*
330    * Determine program name
331    */
332   if (argv[0]) {
333     progname = strrchr(argv[0], '/');
334     if (progname && progname[1])
335       progname++;
336     else
337       progname = argv[0];
338   }
339   if (!progname)
340     progname = "amd";
341   am_set_progname(progname);
342
343   /*
344    * Initialize process id.  This is kept
345    * cached since it is used for generating
346    * and using file handles.
347    */
348   am_set_mypid();
349
350   /*
351    * Get local machine name
352    */
353   if (gethostname(hostname, sizeof(hostname)) < 0) {
354     plog(XLOG_FATAL, "gethostname: %m");
355     going_down(1);
356   }
357   hostname[sizeof(hostname) - 1] = '\0';
358
359   /*
360    * Check it makes sense
361    */
362   if (!*hostname) {
363     plog(XLOG_FATAL, "host name is not set");
364     going_down(1);
365   }
366
367 #ifdef DEBUG
368   /* initialize debugging flags (Register AMQ, Enter daemon mode) */
369   debug_flags = D_AMQ | D_DAEMON;
370 #endif /* DEBUG */
371
372   /*
373    * Initialize global options structure.
374    */
375   init_global_options();
376
377   /*
378    * Partially initialize hostd[].  This
379    * is completed in get_args().
380    */
381   if ((domdot = strchr(hostname, '.'))) {
382     /*
383      * Hostname already contains domainname.
384      * Split out hostname and domainname
385      * components
386      */
387     *domdot++ = '\0';
388     hostdomain = domdot;
389   }
390   strcpy(hostd, hostname);
391   am_set_hostname(hostname);
392
393   /*
394    * Trap interrupts for shutdowns.
395    */
396 #ifdef HAVE_SIGACTION
397   sa.sa_handler = sigterm;
398   sa.sa_flags = 0;
399   sigemptyset(&(sa.sa_mask));
400   sigaddset(&(sa.sa_mask), SIGINT);
401   sigaddset(&(sa.sa_mask), SIGTERM);
402   sigaction(SIGINT, &sa, NULL);
403   sigaction(SIGTERM, &sa, NULL);
404 #else /* not HAVE_SIGACTION */
405   (void) signal(SIGINT, sigterm);
406 #endif /* not HAVE_SIGACTION */
407
408   /*
409    * Trap Terminate so that we can shutdown gracefully (some chance)
410    */
411 #ifdef HAVE_SIGACTION
412   sa.sa_handler = sigterm;
413   sa.sa_flags = 0;
414   sigemptyset(&(sa.sa_mask));
415   sigaddset(&(sa.sa_mask), SIGTERM);
416   sigaction(SIGTERM, &sa, NULL);
417 #else /* not HAVE_SIGACTION */
418   (void) signal(SIGTERM, sigterm);
419 #endif /* not HAVE_SIGACTION */
420
421   /*
422    * Hangups tell us to reload the cache
423    */
424 #ifdef HAVE_SIGACTION
425   sa.sa_handler = sighup;
426   sa.sa_flags = 0;
427   sigemptyset(&(sa.sa_mask));
428   sigaddset(&(sa.sa_mask), SIGHUP);
429   sigaction(SIGHUP, &sa, NULL);
430 #else /* not HAVE_SIGACTION */
431   (void) signal(SIGHUP, sighup);
432 #endif /* not HAVE_SIGACTION */
433
434   /*
435    * Trap Death-of-a-child.  These allow us to
436    * pick up the exit status of backgrounded mounts.
437    * See "sched.c".
438    */
439 #ifdef HAVE_SIGACTION
440   sa.sa_handler = sigchld;
441   sa.sa_flags = 0;
442   sigemptyset(&(sa.sa_mask));
443   sigaddset(&(sa.sa_mask), SIGCHLD);
444   sigaction(SIGCHLD, &sa, NULL);
445
446   /*
447    * construct global "masked_sigs" used in nfs_start.c
448    */
449   sigemptyset(&masked_sigs);
450   sigaddset(&masked_sigs, SIGHUP);
451   sigaddset(&masked_sigs, SIGCHLD);
452   sigaddset(&masked_sigs, SIGTERM);
453   sigaddset(&masked_sigs, SIGINT);
454 #else /* not HAVE_SIGACTION */
455   (void) signal(SIGCHLD, sigchld);
456 #endif /* not HAVE_SIGACTION */
457
458   /*
459    * Fix-up any umask problems.  Most systems default
460    * to 002 which is not too convenient for our purposes
461    */
462   orig_umask = umask(0);
463
464   /*
465    * Figure out primary network name
466    */
467   getwire(&PrimNetName, &PrimNetNum);
468
469   /*
470    * Determine command-line arguments
471    */
472   get_args(argc, argv);
473
474   /*
475    * Log version information.
476    */
477   verstr = strtok(get_version_string(), "\n");
478   plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:");
479   while (verstr) {
480     plog(XLOG_INFO, verstr);
481     verstr = strtok(NULL, "\n");
482   }
483
484   /*
485    * Get our own IP address so that we
486    * can mount the automounter.
487    */
488   amu_get_myaddress(&myipaddr);
489   plog(XLOG_INFO, "My ip addr is %s", inet_ntoa(myipaddr));
490
491   /* avoid hanging on other NFS servers if started elsewhere */
492   if (chdir("/") < 0)
493     plog(XLOG_INFO, "cannot chdir to /: %m");
494
495   /*
496    * Now check we are root.
497    */
498   if (geteuid() != 0) {
499     plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %ld)", (long) geteuid());
500     going_down(1);
501   }
502
503   /*
504    * Lock process text and data segment in memory.
505    */
506 #ifdef HAVE_PLOCK
507   if (gopt.flags & CFM_PROCESS_LOCK) {
508 # ifdef _AIX
509     /*
510      * On AIX you must lower the stack size using ulimit() before calling
511      * plock.  Otherwise plock will reserve a lot of memory space based on
512      * your maximum stack size limit.  Since it is not easily possible to
513      * tell what should the limit be, I print a warning before calling
514      * plock().  See the manual pages for ulimit(1,3,4) on your AIX system.
515      */
516     plog(XLOG_WARNING, "AIX: may need to lower stack size using ulimit(3) before calling plock");
517 # endif /* _AIX */
518     if (plock(PROCLOCK) != 0) {
519       plog(XLOG_WARNING, "Couldn't lock process text and data segment in memory: %m");
520     } else {
521       plog(XLOG_INFO, "Locked process text and data segment in memory");
522     }
523   }
524 #endif /* HAVE_PLOCK */
525
526 #ifdef HAVE_MAP_NIS
527   /*
528    * If the domain was specified then bind it here
529    * to circumvent any default bindings that may
530    * be done in the C library.
531    */
532   if (gopt.nis_domain && yp_bind(gopt.nis_domain)) {
533     plog(XLOG_FATAL, "Can't bind to NIS domain \"%s\"", gopt.nis_domain);
534     going_down(1);
535   }
536 #endif /* HAVE_MAP_NIS */
537
538 #ifdef DEBUG
539   amuDebug(D_DAEMON)
540 #endif /* DEBUG */
541     ppid = daemon_mode();
542
543   sprintf(pid_fsname, "%s:(pid%ld)", am_get_hostname(), (long) am_mypid);
544
545   do_mapc_reload = clocktime() + ONE_HOUR;
546
547   /*
548    * Register automounter with system.
549    */
550   error = mount_automounter(ppid);
551   if (error && ppid)
552     kill(ppid, SIGALRM);
553   going_down(error);
554
555   abort();
556   return 1; /* should never get here */
557 }