]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/amd/amd/amd.c
iicbus(4): Add support for ACPI-based children enumeration
[FreeBSD/FreeBSD.git] / contrib / amd / amd / amd.c
1 /*
2  * Copyright (c) 1997-2014 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. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *
36  * $Id: amd.c,v 1.8.2.6 2004/01/06 03:15:16 ezk Exp $
37  * File: am-utils/amd/amd.c
38  *
39  */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 /*
45  * Automounter
46  */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <amd.h>
53
54 struct amu_global_options gopt; /* where global options are stored */
55
56 char pid_fsname[SIZEOF_PID_FSNAME]; /* "kiska.southseas.nz:(pid%d)" */
57 char *hostdomain = "unknown.domain";
58 #define SIZEOF_HOSTD (2 * MAXHOSTNAMELEN + 1)   /* Host+domain */
59 char hostd[SIZEOF_HOSTD];       /* Host+domain */
60 char *endian = ARCH_ENDIAN;     /* Big or Little endian */
61 char *cpu = HOST_CPU;           /* CPU type */
62 char *PrimNetName;              /* name of primary network */
63 char *PrimNetNum;               /* number of primary network */
64
65 int immediate_abort;            /* Should close-down unmounts be retried */
66 int orig_umask = 022;
67 int select_intr_valid;
68
69 jmp_buf select_intr;
70 struct amd_stats amd_stats;     /* Server statistics */
71 struct in_addr myipaddr;        /* (An) IP address of this host */
72 time_t do_mapc_reload = 0;      /* mapc_reload() call required? */
73
74 #ifdef HAVE_FS_AUTOFS
75 int amd_use_autofs = 0;
76 #endif /* HAVE_FS_AUTOFS */
77
78 #ifdef HAVE_SIGACTION
79 sigset_t masked_sigs;
80 #endif /* HAVE_SIGACTION */
81
82
83 /*
84  * Signal handler:
85  * SIGINT - tells amd to do a full shutdown, including unmounting all
86  *       filesystem.
87  * SIGTERM - tells amd to shutdown now.  Just unmounts the automount nodes.
88  */
89 static RETSIGTYPE
90 sigterm(int sig)
91 {
92 #ifdef REINSTALL_SIGNAL_HANDLER
93   signal(sig, sigterm);
94 #endif /* REINSTALL_SIGNAL_HANDLER */
95
96   switch (sig) {
97   case SIGINT:
98     immediate_abort = 15;
99     break;
100
101   case SIGTERM:
102     immediate_abort = -1;
103     /* fall through... */
104
105   default:
106     plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
107     break;
108   }
109   if (select_intr_valid)
110     longjmp(select_intr, sig);
111 }
112
113
114 /*
115  * Hook for cache reload.
116  * When a SIGHUP arrives it schedules a call to mapc_reload
117  */
118 static RETSIGTYPE
119 sighup(int sig)
120 {
121 #ifdef REINSTALL_SIGNAL_HANDLER
122   signal(sig, sighup);
123 #endif /* REINSTALL_SIGNAL_HANDLER */
124
125   if (sig != SIGHUP)
126     dlog("spurious call to sighup");
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   /*
139    * This signal handler is called during Amd initialization.  The parent
140    * forks a child to do all the hard automounting work, and waits for a
141    * SIGQUIT signal from the child.  When the parent gets the signal it's
142    * supposed to call this handler and exit(3), thus completing the
143    * daemonizing process.  Alas, on some systems, especially Linux 2.4/2.6
144    * with Glibc, exit(3) doesn't always terminate the parent process.
145    * Worse, the parent process now refuses to accept any more SIGQUIT
146    * signals -- they are blocked.  What's really annoying is that this
147    * doesn't happen all the time, suggesting a race condition somewhere.
148    * (This happens even if I change the logic to use another signal.)  I
149    * traced this to something which exit(3) does in addition to exiting the
150    * process, probably some atexit() stuff or other side-effects related to
151    * signal handling.  Either way, since at this stage the parent process
152    * just needs to terminate, I'm simply calling _exit(2).  Note also that
153    * the OpenGroup doesn't list exit(3) as a recommended "Base Interface"
154    * but they do list _exit(2) as one.  This fix seems to work reliably all
155    * the time. -Erez (2/27/2005)
156    */
157   _exit(0);
158 }
159
160
161 static int
162 daemon_mode(void)
163 {
164   int bgpid;
165
166 #ifdef HAVE_SIGACTION
167   struct sigaction sa, osa;
168
169   memset(&sa, 0, sizeof(sa));
170   sa.sa_handler = parent_exit;
171   sa.sa_flags = 0;
172   sigemptyset(&(sa.sa_mask));
173   sigaddset(&(sa.sa_mask), SIGQUIT);
174   sigaction(SIGQUIT, &sa, &osa);
175 #else /* not HAVE_SIGACTION */
176   signal(SIGQUIT, parent_exit);
177 #endif /* not HAVE_SIGACTION */
178
179   bgpid = background();
180
181   if (bgpid != 0) {
182     /*
183      * Now wait for the automount points to
184      * complete.
185      */
186     for (;;)
187       pause();
188     /* should never reach here */
189   }
190 #ifdef HAVE_SIGACTION
191   sigaction(SIGQUIT, &osa, NULL);
192 #else /* not HAVE_SIGACTION */
193   signal(SIGQUIT, SIG_DFL);
194 #endif /* not HAVE_SIGACTION */
195
196   /*
197    * Record our pid to make it easier to kill the correct amd.
198    */
199   if (gopt.flags & CFM_PRINT_PID) {
200     if (STREQ(gopt.pid_file, "/dev/stdout")) {
201       printf("%ld\n", (long) am_mypid);
202       /* flush stdout, just in case */
203       fflush(stdout);
204     } else {
205       FILE *f;
206       mode_t prev_umask = umask(0022); /* set secure temporary umask */
207
208       f = fopen(gopt.pid_file, "w");
209       if (f) {
210         fprintf(f, "%ld\n", (long) am_mypid);
211         (void) fclose(f);
212       } else {
213         fprintf(stderr, "cannot open %s (errno=%d)\n", gopt.pid_file, errno);
214       }
215       umask(prev_umask);        /* restore umask */
216     }
217   }
218
219   /*
220    * Pretend we are in the foreground again
221    */
222   foreground = 1;
223
224   /*
225    * Dissociate from the controlling terminal
226    */
227   amu_release_controlling_tty();
228
229   return getppid();
230 }
231
232
233 /*
234  * Initialize global options structure.
235  */
236 static void
237 init_global_options(void)
238 {
239 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
240   static struct utsname un;
241 #endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
242   int i;
243
244   memset(&gopt, 0, sizeof(struct amu_global_options));
245
246   /* name of current architecture */
247   gopt.arch = HOST_ARCH;
248
249   /* automounter temp dir */
250   gopt.auto_dir = "/.amd_mnt";
251
252   /* toplevel attribute cache timeout */
253   gopt.auto_attrcache = 0;
254
255   /* cluster name */
256   gopt.cluster = NULL;
257
258   /* executable map timeout */
259   gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT;
260
261   /*
262    * kernel architecture: this you must get from uname() if possible.
263    */
264 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
265   if (uname(&un) >= 0)
266     gopt.karch = un.machine;
267   else
268 #endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
269     gopt.karch = HOST_ARCH;
270
271   /* amd log file */
272   gopt.logfile = NULL;
273
274   /* operating system name */
275   gopt.op_sys = HOST_OS_NAME;
276
277   /* OS version */
278   gopt.op_sys_ver = HOST_OS_VERSION;
279
280   /* full OS name and version */
281   gopt.op_sys_full = HOST_OS;
282
283   /* OS version */
284   gopt.op_sys_vendor = HOST_VENDOR;
285
286   /* pid file */
287   gopt.pid_file = "/dev/stdout";
288
289   /* local domain */
290   gopt.sub_domain = NULL;
291
292   /* reset NFS (and toplvl) retransmit counter and retry interval */
293   for (i=0; i<AMU_TYPE_MAX; ++i) {
294     gopt.amfs_auto_retrans[i] = -1; /* -1 means "never set before" */
295     gopt.amfs_auto_timeo[i] = -1; /* -1 means "never set before" */
296   }
297
298   /* cache duration */
299   gopt.am_timeo = AM_TTL;
300
301   /* dismount interval */
302   gopt.am_timeo_w = AM_TTL_W;
303
304   /* map reload intervl */
305   gopt.map_reload_interval = ONE_HOUR;
306
307   /*
308    * various CFM_* flags that are on by default.
309    */
310   gopt.flags = CFM_DEFAULT_FLAGS;
311
312 #ifdef HAVE_MAP_HESIOD
313   /* Hesiod rhs zone */
314   gopt.hesiod_base = "automount";
315 #endif /* HAVE_MAP_HESIOD */
316
317 #ifdef HAVE_MAP_LDAP
318   /* LDAP base */
319   gopt.ldap_base = NULL;
320
321   /* LDAP host ports */
322   gopt.ldap_hostports = NULL;
323
324   /* LDAP cache */
325   gopt.ldap_cache_seconds = 0;
326   gopt.ldap_cache_maxmem = 131072;
327
328   /* LDAP protocol version */
329   gopt.ldap_proto_version = 2;
330 #endif /* HAVE_MAP_LDAP */
331
332 #ifdef HAVE_MAP_NIS
333   /* YP domain name */
334   gopt.nis_domain = NULL;
335 #endif /* HAVE_MAP_NIS */
336 }
337
338
339 /*
340  * Lock process text and data segment in memory (after forking the daemon)
341  */
342 static void
343 do_memory_locking(void)
344 {
345 #if defined(HAVE_PLOCK) || defined(HAVE_MLOCKALL)
346   int locked_ok = 0;
347 #else /* not HAVE_PLOCK and not HAVE_MLOCKALL */
348   plog(XLOG_WARNING, "Process memory locking not supported by the OS");
349 #endif /* not HAVE_PLOCK and not HAVE_MLOCKALL */
350 #ifdef HAVE_PLOCK
351 # ifdef _AIX
352   /*
353    * On AIX you must lower the stack size using ulimit() before calling
354    * plock.  Otherwise plock will reserve a lot of memory space based on
355    * your maximum stack size limit.  Since it is not easily possible to
356    * tell what should the limit be, I print a warning before calling
357    * plock().  See the manual pages for ulimit(1,3,4) on your AIX system.
358    */
359   plog(XLOG_WARNING, "AIX: may need to lower stack size using ulimit(3) before calling plock");
360 # endif /* _AIX */
361   if (!locked_ok && plock(PROCLOCK) != 0)
362     plog(XLOG_WARNING, "Couldn't lock process pages in memory using plock(): %m");
363   else
364     locked_ok = 1;
365 #endif /* HAVE_PLOCK */
366 #ifdef HAVE_MLOCKALL
367   if (!locked_ok && mlockall(MCL_CURRENT|MCL_FUTURE) != 0)
368     plog(XLOG_WARNING, "Couldn't lock process pages in memory using mlockall(): %m");
369   else
370     locked_ok = 1;
371 #endif /* HAVE_MLOCKALL */
372 #if defined(HAVE_PLOCK) || defined(HAVE_MLOCKALL)
373   if (locked_ok)
374     plog(XLOG_INFO, "Locked process pages in memory");
375 #endif /* HAVE_PLOCK || HAVE_MLOCKALL */
376
377 #if defined(HAVE_MADVISE) && defined(MADV_PROTECT)
378     madvise(NULL, 0, MADV_PROTECT); /* may be redundant of the above worked out */
379 #endif /* defined(HAVE_MADVISE) && defined(MADV_PROTECT) */
380 }
381
382
383 int
384 main(int argc, char *argv[])
385 {
386   char *domdot, *verstr, *vertmp;
387   int ppid = 0;
388   int error;
389   char *progname = NULL;                /* "amd" */
390   char hostname[MAXHOSTNAMELEN + 1] = "localhost"; /* Hostname */
391
392   /*
393    * Make sure some built-in assumptions are true before we start
394    */
395   assert(sizeof(nfscookie) >= sizeof(u_int));
396   assert(sizeof(int) >= 4);
397
398   /*
399    * Set processing status.
400    */
401   amd_state = Start;
402
403   /*
404    * Determine program name
405    */
406   if (argv[0]) {
407     progname = strrchr(argv[0], '/');
408     if (progname && progname[1])
409       progname++;
410     else
411       progname = argv[0];
412   }
413   if (!progname)
414     progname = "amd";
415   am_set_progname(progname);
416
417   plog(XLOG_WARNING, "built-in amd in FreeBSD is deprecated and will be removed before FreeBSD 13");
418
419   /*
420    * Initialize process id.  This is kept
421    * cached since it is used for generating
422    * and using file handles.
423    */
424   am_set_mypid();
425
426   /*
427    * Get local machine name
428    */
429   if (gethostname(hostname, sizeof(hostname)) < 0) {
430     plog(XLOG_FATAL, "gethostname: %m");
431     going_down(1);
432     return 1;
433   }
434   hostname[sizeof(hostname) - 1] = '\0';
435
436   /*
437    * Check it makes sense
438    */
439   if (!*hostname) {
440     plog(XLOG_FATAL, "host name is not set");
441     going_down(1);
442     return 1;
443   }
444
445   /*
446    * Initialize global options structure.
447    */
448   init_global_options();
449
450   /*
451    * Partially initialize hostd[].  This
452    * is completed in get_args().
453    */
454   if ((domdot = strchr(hostname, '.'))) {
455     /*
456      * Hostname already contains domainname.
457      * Split out hostname and domainname
458      * components
459      */
460     *domdot++ = '\0';
461     hostdomain = domdot;
462   }
463   xstrlcpy(hostd, hostname, sizeof(hostd));
464   am_set_hostname(hostname);
465
466   /*
467    * Setup signal handlers
468    */
469   /* SIGINT: trap interrupts for shutdowns */
470   setup_sighandler(SIGINT, sigterm);
471   /* SIGTERM: trap terminate so we can shutdown cleanly (some chance) */
472   setup_sighandler(SIGTERM, sigterm);
473   /* SIGHUP: hangups tell us to reload the cache */
474   setup_sighandler(SIGHUP, sighup);
475   /*
476    * SIGCHLD: trap Death-of-a-child.  These allow us to pick up the exit
477    * status of backgrounded mounts.  See "sched.c".
478    */
479   setup_sighandler(SIGCHLD, sigchld);
480 #ifdef HAVE_SIGACTION
481   /* construct global "masked_sigs" used in nfs_start.c */
482   sigemptyset(&masked_sigs);
483   sigaddset(&masked_sigs, SIGINT);
484   sigaddset(&masked_sigs, SIGTERM);
485   sigaddset(&masked_sigs, SIGHUP);
486   sigaddset(&masked_sigs, SIGCHLD);
487 #endif /* HAVE_SIGACTION */
488
489   /*
490    * Fix-up any umask problems.  Most systems default
491    * to 002 which is not too convenient for our purposes
492    */
493   orig_umask = umask(0);
494
495   /*
496    * Figure out primary network name
497    */
498   getwire(&PrimNetName, &PrimNetNum);
499
500   /*
501    * Determine command-line arguments.
502    * (Also initialize amd.conf parameters, maps, and more.)
503    */
504   get_args(argc, argv);
505
506   /*
507    * Log version information.
508    */
509   vertmp = get_version_string();
510   verstr = strtok(vertmp, "\n");
511   plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:");
512   while (verstr) {
513     plog(XLOG_INFO, "%s", verstr);
514     verstr = strtok(NULL, "\n");
515   }
516   XFREE(vertmp);
517
518   /*
519    * Get our own IP address so that we can mount the automounter.  We pass
520    * localhost_address which could be used as the default localhost
521    * name/address in amu_get_myaddress().
522    */
523   amu_get_myaddress(&myipaddr, gopt.localhost_address);
524   plog(XLOG_INFO, "My ip addr is %s", inet_ntoa(myipaddr));
525
526   /* avoid hanging on other NFS servers if started elsewhere */
527   if (chdir("/") < 0)
528     plog(XLOG_INFO, "cannot chdir to /: %m");
529
530   /*
531    * Now check we are root.
532    */
533   if (geteuid() != 0) {
534     plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %ld)", (long) geteuid());
535     going_down(1);
536     return 1;
537   }
538
539 #ifdef HAVE_MAP_NIS
540   /*
541    * If the domain was specified then bind it here
542    * to circumvent any default bindings that may
543    * be done in the C library.
544    */
545   if (gopt.nis_domain && yp_bind(gopt.nis_domain)) {
546     plog(XLOG_FATAL, "Can't bind to NIS domain \"%s\"", gopt.nis_domain);
547     going_down(1);
548     return 1;
549   }
550 #endif /* HAVE_MAP_NIS */
551
552   if (amuDebug(D_DAEMON))
553     ppid = daemon_mode();
554
555   /*
556    * Lock process text and data segment in memory.
557    */
558   if (gopt.flags & CFM_PROCESS_LOCK) {
559     do_memory_locking();
560   }
561
562   do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
563
564   /*
565    * Register automounter with system.
566    */
567   error = mount_automounter(ppid);
568   if (error && ppid)
569     kill(ppid, SIGALRM);
570
571 #ifdef HAVE_FS_AUTOFS
572   /*
573    * XXX this should be part of going_down(), but I can't move it there
574    * because it would be calling non-library code from the library... ugh
575    */
576   if (amd_use_autofs)
577     destroy_autofs_service();
578 #endif /* HAVE_FS_AUTOFS */
579
580   going_down(error);
581
582   abort();
583   return 1; /* should never get here */
584 }