Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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  * $DragonFly: src/contrib/amd/amd/amd.c,v 1.2 2003/06/17 04:23:56 dillon Exp $
44  *
45  */
46
47 /*
48  * Automounter
49  */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif /* HAVE_CONFIG_H */
54 #include <am_defs.h>
55 #include <amd.h>
56
57 struct amu_global_options gopt; /* where global options are stored */
58
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 */
66
67 int immediate_abort;            /* Should close-down unmounts be retried */
68 int orig_umask = 022;
69 int select_intr_valid;
70
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? */
75
76 #ifdef HAVE_SIGACTION
77 sigset_t masked_sigs;
78 #endif /* HAVE_SIGACTION */
79
80
81 /*
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.
86  */
87 static RETSIGTYPE
88 sigterm(int sig)
89 {
90 #ifdef REINSTALL_SIGNAL_HANDLER
91   signal(sig, sigterm);
92 #endif /* REINSTALL_SIGNAL_HANDLER */
93
94   switch (sig) {
95   case SIGINT:
96     immediate_abort = 15;
97     break;
98
99   case SIGTERM:
100     immediate_abort = -1;
101     /* fall through... */
102
103   default:
104     plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
105     break;
106   }
107   if (select_intr_valid)
108     longjmp(select_intr, sig);
109 }
110
111
112 /*
113  * Hook for cache reload.
114  * When a SIGHUP arrives it schedules a call to mapc_reload
115  */
116 static RETSIGTYPE
117 sighup(int sig)
118 {
119 #ifdef REINSTALL_SIGNAL_HANDLER
120   signal(sig, sighup);
121 #endif /* REINSTALL_SIGNAL_HANDLER */
122
123 #ifdef DEBUG
124   if (sig != SIGHUP)
125     dlog("spurious call to sighup");
126 #endif /* DEBUG */
127   /*
128    * Force a reload by zero'ing the timer
129    */
130   if (amd_state == Run)
131     do_mapc_reload = 0;
132 }
133
134
135 static RETSIGTYPE
136 parent_exit(int sig)
137 {
138   exit(0);
139 }
140
141
142 static int
143 daemon_mode(void)
144 {
145   int bgpid;
146
147 #ifdef HAVE_SIGACTION
148   struct sigaction sa, osa;
149
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 */
158
159   bgpid = background();
160
161   if (bgpid != 0) {
162     /*
163      * Now wait for the automount points to
164      * complete.
165      */
166     for (;;)
167       pause();
168     /* should never reach here */
169   }
170 #ifdef HAVE_SIGACTION
171   sigaction(SIGQUIT, &osa, NULL);
172 #else /* not HAVE_SIGACTION */
173   signal(SIGQUIT, SIG_DFL);
174 #endif /* not HAVE_SIGACTION */
175
176   /*
177    * Record our pid to make it easier to kill the correct amd.
178    */
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 */
187
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);
194       }
195       umask(prev_umask);        /* restore umask */
196     }
197   }
198
199   /*
200    * Pretend we are in the foreground again
201    */
202   foreground = 1;
203
204   /*
205    * Dissociate from the controlling terminal
206    */
207   amu_release_controlling_tty();
208
209   return getppid();
210 }
211
212
213 /*
214  * Initialize global options structure.
215  */
216 static void
217 init_global_options(void)
218 {
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) */
222
223   memset(&gopt, 0, sizeof(struct amu_global_options));
224
225   /* name of current architecture */
226   gopt.arch = HOST_ARCH;
227
228   /* automounter temp dir */
229   gopt.auto_dir = "/.amd_mnt";
230
231   /* cluster name */
232   gopt.cluster = NULL;
233
234   /*
235    * kernel architecture: this you must get from uname() if possible.
236    */
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;
243
244   /* amd log file */
245   gopt.logfile = NULL;
246
247   /* operating system name */
248   gopt.op_sys = HOST_OS_NAME;
249
250   /* OS version */
251   gopt.op_sys_ver = HOST_OS_VERSION;
252
253   /* full OS name and version */
254   gopt.op_sys_full = HOST_OS;
255
256   /* OS version */
257   gopt.op_sys_vendor = HOST_VENDOR;
258
259   /* pid file */
260   gopt.pid_file = "/dev/stdout";
261
262   /* local domain */
263   gopt.sub_domain = NULL;
264
265   /* NFS retransmit counter */
266   gopt.amfs_auto_retrans = -1;
267
268   /* NFS retry interval */
269   gopt.amfs_auto_timeo = -1;
270
271   /* cache duration */
272   gopt.am_timeo = AM_TTL;
273
274   /* dismount interval */
275   gopt.am_timeo_w = AM_TTL_W;
276
277   /*
278    * various CFM_* flags.
279    * by default, only the "plock" option is on (if available).
280    */
281   gopt.flags = CFM_PROCESS_LOCK;
282
283 #ifdef HAVE_MAP_HESIOD
284   /* Hesiod rhs zone */
285   gopt.hesiod_base = "automount";
286 #endif /* HAVE_MAP_HESIOD */
287
288 #ifdef HAVE_MAP_LDAP
289   /* LDAP base */
290   gopt.ldap_base = NULL;
291
292   /* LDAP host ports */
293   gopt.ldap_hostports = NULL;
294
295   /* LDAP cache */
296   gopt.ldap_cache_seconds = 0;
297   gopt.ldap_cache_maxmem = 131072;
298 #endif /* HAVE_MAP_LDAP */
299
300 #ifdef HAVE_MAP_NIS
301   /* YP domain name */
302   gopt.nis_domain = NULL;
303 #endif /* HAVE_MAP_NIS */
304 }
305
306
307 int
308 main(int argc, char *argv[])
309 {
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 */
318
319   /*
320    * Make sure some built-in assumptions are true before we start
321    */
322   assert(sizeof(nfscookie) >= sizeof(u_int));
323   assert(sizeof(int) >= 4);
324
325   /*
326    * Set processing status.
327    */
328   amd_state = Start;
329
330   /*
331    * Determine program name
332    */
333   if (argv[0]) {
334     progname = strrchr(argv[0], '/');
335     if (progname && progname[1])
336       progname++;
337     else
338       progname = argv[0];
339   }
340   if (!progname)
341     progname = "amd";
342   am_set_progname(progname);
343
344   /*
345    * Initialize process id.  This is kept
346    * cached since it is used for generating
347    * and using file handles.
348    */
349   am_set_mypid();
350
351   /*
352    * Get local machine name
353    */
354   if (gethostname(hostname, sizeof(hostname)) < 0) {
355     plog(XLOG_FATAL, "gethostname: %m");
356     going_down(1);
357   }
358   hostname[sizeof(hostname) - 1] = '\0';
359
360   /*
361    * Check it makes sense
362    */
363   if (!*hostname) {
364     plog(XLOG_FATAL, "host name is not set");
365     going_down(1);
366   }
367
368 #ifdef DEBUG
369   /* initialize debugging flags (Register AMQ, Enter daemon mode) */
370   debug_flags = D_AMQ | D_DAEMON;
371 #endif /* DEBUG */
372
373   /*
374    * Initialize global options structure.
375    */
376   init_global_options();
377
378   /*
379    * Partially initialize hostd[].  This
380    * is completed in get_args().
381    */
382   if ((domdot = strchr(hostname, '.'))) {
383     /*
384      * Hostname already contains domainname.
385      * Split out hostname and domainname
386      * components
387      */
388     *domdot++ = '\0';
389     hostdomain = domdot;
390   }
391   strcpy(hostd, hostname);
392   am_set_hostname(hostname);
393
394   /*
395    * Trap interrupts for shutdowns.
396    */
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 */
408
409   /*
410    * Trap Terminate so that we can shutdown gracefully (some chance)
411    */
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 */
421
422   /*
423    * Hangups tell us to reload the cache
424    */
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 */
434
435   /*
436    * Trap Death-of-a-child.  These allow us to
437    * pick up the exit status of backgrounded mounts.
438    * See "sched.c".
439    */
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);
446
447   /*
448    * construct global "masked_sigs" used in nfs_start.c
449    */
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 */
458
459   /*
460    * Fix-up any umask problems.  Most systems default
461    * to 002 which is not too convenient for our purposes
462    */
463   orig_umask = umask(0);
464
465   /*
466    * Figure out primary network name
467    */
468   getwire(&PrimNetName, &PrimNetNum);
469
470   /*
471    * Determine command-line arguments
472    */
473   get_args(argc, argv);
474
475   /*
476    * Log version information.
477    */
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");
483   }
484
485   /*
486    * Get our own IP address so that we
487    * can mount the automounter.
488    */
489   amu_get_myaddress(&myipaddr);
490   plog(XLOG_INFO, "My ip addr is %s", inet_ntoa(myipaddr));
491
492   /* avoid hanging on other NFS servers if started elsewhere */
493   if (chdir("/") < 0)
494     plog(XLOG_INFO, "cannot chdir to /: %m");
495
496   /*
497    * Now check we are root.
498    */
499   if (geteuid() != 0) {
500     plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %ld)", (long) geteuid());
501     going_down(1);
502   }
503
504   /*
505    * Lock process text and data segment in memory.
506    */
507 #ifdef HAVE_PLOCK
508   if (gopt.flags & CFM_PROCESS_LOCK) {
509 # ifdef _AIX
510     /*
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.
516      */
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");
523     }
524   }
525 #endif /* HAVE_PLOCK */
526
527 #ifdef HAVE_MAP_NIS
528   /*
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.
532    */
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);
536   }
537 #endif /* HAVE_MAP_NIS */
538
539 #ifdef DEBUG
540   amuDebug(D_DAEMON)
541 #endif /* DEBUG */
542     ppid = daemon_mode();
543
544   sprintf(pid_fsname, "%s:(pid%ld)", am_get_hostname(), (long) am_mypid);
545
546   do_mapc_reload = clocktime() + ONE_HOUR;
547
548   /*
549    * Register automounter with system.
550    */
551   error = mount_automounter(ppid);
552   if (error && ppid)
553     kill(ppid, SIGALRM);
554   going_down(error);
555
556   abort();
557   return 1; /* should never get here */
558 }