Am-Utils Cross Reference
am-utils/amd/amd.c

source navigation ]
diff markup ]
identifier search ]
freetext search ]
file search ]
 
Version: 6.0.1 ] [ 6.0.2 ] [ 6.0.3 ] [ 6.0.4 ] [ 6.0.5 ] [ 6.0.6 ] [ 6.0.7 ] [ 6.0.8 ] [ 6.0.9 ] [ 6.0.10 ] [ 6.1 ] [ 6.1.1 ]

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
This page is hosted at the Filesystems and Storage Lab at Stony Brook.