xref: /netbsd/external/bsd/am-utils/dist/hlfsd/hlfsd.c (revision 23de60b7)
1*23de60b7Schristos /*	$NetBSD: hlfsd.c,v 1.3 2015/01/17 17:46:31 christos Exp $	*/
2a53f50b9Schristos 
3a53f50b9Schristos /*
4*23de60b7Schristos  * Copyright (c) 1997-2014 Erez Zadok
5a53f50b9Schristos  * Copyright (c) 1989 Jan-Simon Pendry
6a53f50b9Schristos  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7a53f50b9Schristos  * Copyright (c) 1989 The Regents of the University of California.
8a53f50b9Schristos  * All rights reserved.
9a53f50b9Schristos  *
10a53f50b9Schristos  * This code is derived from software contributed to Berkeley by
11a53f50b9Schristos  * Jan-Simon Pendry at Imperial College, London.
12a53f50b9Schristos  *
13a53f50b9Schristos  * Redistribution and use in source and binary forms, with or without
14a53f50b9Schristos  * modification, are permitted provided that the following conditions
15a53f50b9Schristos  * are met:
16a53f50b9Schristos  * 1. Redistributions of source code must retain the above copyright
17a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer.
18a53f50b9Schristos  * 2. Redistributions in binary form must reproduce the above copyright
19a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer in the
20a53f50b9Schristos  *    documentation and/or other materials provided with the distribution.
21*23de60b7Schristos  * 3. Neither the name of the University nor the names of its contributors
22a53f50b9Schristos  *    may be used to endorse or promote products derived from this software
23a53f50b9Schristos  *    without specific prior written permission.
24a53f50b9Schristos  *
25a53f50b9Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26a53f50b9Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27a53f50b9Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28a53f50b9Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29a53f50b9Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30a53f50b9Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31a53f50b9Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32a53f50b9Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33a53f50b9Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34a53f50b9Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35a53f50b9Schristos  * SUCH DAMAGE.
36a53f50b9Schristos  *
37a53f50b9Schristos  *
38a53f50b9Schristos  * File: am-utils/hlfsd/hlfsd.c
39a53f50b9Schristos  *
40a53f50b9Schristos  * HLFSD was written at Columbia University Computer Science Department, by
41a53f50b9Schristos  * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
42a53f50b9Schristos  * It is being distributed under the same terms and conditions as amd does.
43a53f50b9Schristos  */
44a53f50b9Schristos 
45a53f50b9Schristos #ifdef HAVE_CONFIG_H
46a53f50b9Schristos # include <config.h>
47a53f50b9Schristos #endif /* HAVE_CONFIG_H */
48a53f50b9Schristos #include <am_defs.h>
49a53f50b9Schristos #include <hlfsd.h>
50a53f50b9Schristos 
51a53f50b9Schristos /*
52a53f50b9Schristos  * STATIC VARIABLES:
53a53f50b9Schristos  */
54a53f50b9Schristos static RETSIGTYPE proceed(int);
55a53f50b9Schristos static RETSIGTYPE reaper(int);
56a53f50b9Schristos static RETSIGTYPE reload(int);
57a53f50b9Schristos static char *hlfs_group = DEFAULT_HLFS_GROUP;
58a53f50b9Schristos static char default_dir_name[] = DEFAULT_DIRNAME;
59a53f50b9Schristos static char *dir_name = default_dir_name;
60a53f50b9Schristos static int printpid = 0;
61a53f50b9Schristos static int stoplight = 0;
62a53f50b9Schristos static void hlfsd_init(void);
63a53f50b9Schristos static void usage(void);
64a53f50b9Schristos 
65a53f50b9Schristos static struct itimerval reloadinterval = {
66a53f50b9Schristos   {DEFAULT_INTERVAL, 0},
67a53f50b9Schristos   {DEFAULT_INTERVAL, 0}
68a53f50b9Schristos };
69a53f50b9Schristos 
70a53f50b9Schristos /*
71a53f50b9Schristos  * default mount options.
72a53f50b9Schristos  */
73a53f50b9Schristos static char default_mntopts[] = "ro,noac";
74a53f50b9Schristos 
75a53f50b9Schristos /*
76a53f50b9Schristos  * GLOBALS:
77a53f50b9Schristos  */
78a53f50b9Schristos SVCXPRT *nfsxprt;
79a53f50b9Schristos char *alt_spooldir = ALT_SPOOLDIR;
80a53f50b9Schristos char *home_subdir = HOME_SUBDIR;
81a53f50b9Schristos char *logfile = DEFAULT_LOGFILE;
82a53f50b9Schristos char *passwdfile = NULL;	/* alternate passwd file to use */
83a53f50b9Schristos char *slinkname = NULL;
84a53f50b9Schristos char hostname[MAXHOSTNAMELEN + 1] = "localhost";
85a53f50b9Schristos u_int cache_interval = DEFAULT_CACHE_INTERVAL;
86a53f50b9Schristos gid_t hlfs_gid = (gid_t) INVALIDID;
87a53f50b9Schristos int masterpid = 0;
88a53f50b9Schristos int noverify = 0;
89a53f50b9Schristos int orig_umask = 022;
90a53f50b9Schristos int serverpid = 0;
91a53f50b9Schristos nfstime startup;
92a53f50b9Schristos u_short nfs_port;
93a53f50b9Schristos 
94a53f50b9Schristos /* symbol must be available always */
95a53f50b9Schristos #ifdef MNTTAB_FILE_NAME
96a53f50b9Schristos char *mnttab_file_name = MNTTAB_FILE_NAME;
97a53f50b9Schristos #else /* not MNTTAB_FILE_NAME */
98a53f50b9Schristos char *mnttab_file_name = NULL;
99a53f50b9Schristos #endif /* not MNTTAB_FILE_NAME */
100a53f50b9Schristos 
101a53f50b9Schristos /* forward declarations */
102a53f50b9Schristos void hlfsd_going_down(int rc);
103a53f50b9Schristos void fatalerror(char *str);
104a53f50b9Schristos 
105a53f50b9Schristos 
106a53f50b9Schristos static void
usage(void)107a53f50b9Schristos usage(void)
108a53f50b9Schristos {
109a53f50b9Schristos   fprintf(stderr,
110a53f50b9Schristos 	  "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
111a53f50b9Schristos 	  am_get_progname());
112a53f50b9Schristos   fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
113a53f50b9Schristos   show_opts('x', xlog_opt);
114a53f50b9Schristos #ifdef DEBUG
115a53f50b9Schristos   show_opts('D', dbg_opt);
116a53f50b9Schristos #endif /* DEBUG */
117a53f50b9Schristos   fprintf(stderr, "\t[dir_name [subdir]]\n");
118a53f50b9Schristos   exit(2);
119a53f50b9Schristos }
120a53f50b9Schristos 
121a53f50b9Schristos 
122a53f50b9Schristos void
fatalerror(char * str)123a53f50b9Schristos fatalerror(char *str)
124a53f50b9Schristos {
125a53f50b9Schristos #define ERRM ": %m"
126a53f50b9Schristos   size_t l = strlen(str) + sizeof(ERRM) - 1;
127a53f50b9Schristos   char *tmp = strnsave(str, l);
128a53f50b9Schristos   xstrlcat(tmp, ERRM, l);
129a53f50b9Schristos   fatal(tmp);
130a53f50b9Schristos }
131a53f50b9Schristos 
132a53f50b9Schristos 
133a53f50b9Schristos int
main(int argc,char * argv[])134a53f50b9Schristos main(int argc, char *argv[])
135a53f50b9Schristos {
136a53f50b9Schristos   char *dot;
137a53f50b9Schristos   char *mntopts = (char *) NULL;
138a53f50b9Schristos   char hostpid_fs[MAXHOSTNAMELEN + 1 + 16];	/* room for ":(pid###)" */
139a53f50b9Schristos   char progpid_fs[PROGNAMESZ + 1 + 11];		/* room for ":pid" */
140a53f50b9Schristos   char preopts[128];
141a53f50b9Schristos   char *progname;
142a53f50b9Schristos   int forcecache = 0;
143a53f50b9Schristos   int forcefast = 0;
144a53f50b9Schristos   int genflags = 0;
145a53f50b9Schristos   int opt, ret;
146a53f50b9Schristos   int opterrs = 0;
147a53f50b9Schristos   int retry;
148a53f50b9Schristos   int soNFS;			/* NFS socket */
149a53f50b9Schristos   mntent_t mnt;
150a53f50b9Schristos   nfs_args_t nfs_args;
151a53f50b9Schristos   am_nfs_handle_t anh;
152a53f50b9Schristos   struct dirent *direntry;
153a53f50b9Schristos   struct group *grp;
154a53f50b9Schristos   struct stat stmodes;
155a53f50b9Schristos   DIR *mountdir;
156a53f50b9Schristos   MTYPE_TYPE type = MOUNT_TYPE_NFS;
157a53f50b9Schristos 
158a53f50b9Schristos #ifdef HAVE_SIGACTION
159a53f50b9Schristos   struct sigaction sa;
160a53f50b9Schristos #endif /* not HAVE_SIGACTION */
161a53f50b9Schristos 
162a53f50b9Schristos #ifndef HAVE_TRANSPORT_TYPE_TLI
163a53f50b9Schristos   struct sockaddr_in localsocket;
164a53f50b9Schristos #endif /* not HAVE_TRANSPORT_TYPE_TLI */
165a53f50b9Schristos 
166a53f50b9Schristos 
167a53f50b9Schristos   /* get program name and truncate so we don't overflow progpid_fs */
168a53f50b9Schristos 
169a53f50b9Schristos   if ((progname = strrchr(argv[0], '/')) != NULL)
170a53f50b9Schristos     progname++;
171a53f50b9Schristos   else
172a53f50b9Schristos     progname = argv[0];
173a53f50b9Schristos   if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
174a53f50b9Schristos     progname[PROGNAMESZ] = '\0';
175a53f50b9Schristos   am_set_progname(progname);
176a53f50b9Schristos 
177a53f50b9Schristos   while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
178a53f50b9Schristos     switch (opt) {
179a53f50b9Schristos 
180a53f50b9Schristos     case 'a':
181a53f50b9Schristos       if (!optarg || optarg[0] != '/') {
182a53f50b9Schristos 	printf("%s: invalid directory for -a: %s\n",
183a53f50b9Schristos 	       am_get_progname(), optarg);
184a53f50b9Schristos 	exit(3);
185a53f50b9Schristos       }
186a53f50b9Schristos       alt_spooldir = optarg;
187a53f50b9Schristos       break;
188a53f50b9Schristos 
189a53f50b9Schristos     case 'c':
190a53f50b9Schristos       if (!atoi(optarg)) {
191a53f50b9Schristos 	printf("%s: invalid interval for -c: %s\n",
192a53f50b9Schristos 	       am_get_progname(), optarg);
193a53f50b9Schristos 	exit(3);
194a53f50b9Schristos       }
195a53f50b9Schristos       cache_interval = atoi(optarg);
196a53f50b9Schristos       break;
197a53f50b9Schristos 
198a53f50b9Schristos     case 'C':
199a53f50b9Schristos       forcecache++;
200a53f50b9Schristos       break;
201a53f50b9Schristos 
202a53f50b9Schristos     case 'f':
203a53f50b9Schristos       forcefast++;
204a53f50b9Schristos       break;
205a53f50b9Schristos 
206a53f50b9Schristos     case 'g':
207a53f50b9Schristos       hlfs_group = optarg;
208a53f50b9Schristos       break;
209a53f50b9Schristos 
210a53f50b9Schristos     case 'i':
211a53f50b9Schristos       if (!atoi(optarg)) {
212a53f50b9Schristos 	printf("%s: invalid interval for -i: %s\n",
213a53f50b9Schristos 	       am_get_progname(), optarg);
214a53f50b9Schristos 	exit(3);
215a53f50b9Schristos       }
216a53f50b9Schristos       reloadinterval.it_interval.tv_sec = atoi(optarg);
217a53f50b9Schristos       reloadinterval.it_value.tv_sec = atoi(optarg);
218a53f50b9Schristos       break;
219a53f50b9Schristos 
220a53f50b9Schristos     case 'l':
221a53f50b9Schristos       logfile = optarg;
222a53f50b9Schristos       break;
223a53f50b9Schristos 
224a53f50b9Schristos     case 'n':
225a53f50b9Schristos       noverify++;
226a53f50b9Schristos       break;
227a53f50b9Schristos 
228a53f50b9Schristos     case 'o':
229a53f50b9Schristos       mntopts = optarg;
230a53f50b9Schristos       break;
231a53f50b9Schristos 
232a53f50b9Schristos     case 'p':
233a53f50b9Schristos       printpid++;
234a53f50b9Schristos       break;
235a53f50b9Schristos 
236a53f50b9Schristos     case 'P':
237a53f50b9Schristos       passwdfile = optarg;
238a53f50b9Schristos       break;
239a53f50b9Schristos 
240a53f50b9Schristos     case 'v':
241a53f50b9Schristos       fprintf(stderr, "%s\n", HLFSD_VERSION);
242a53f50b9Schristos       exit(0);
243a53f50b9Schristos 
244a53f50b9Schristos     case 'x':
245a53f50b9Schristos       opterrs += switch_option(optarg);
246a53f50b9Schristos       break;
247a53f50b9Schristos 
248a53f50b9Schristos     case 'D':
249a53f50b9Schristos #ifdef DEBUG
250a53f50b9Schristos       opterrs += debug_option(optarg);
251a53f50b9Schristos #else /* not DEBUG */
252a53f50b9Schristos       fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
253a53f50b9Schristos #endif /* not DEBUG */
254a53f50b9Schristos       break;
255a53f50b9Schristos 
256a53f50b9Schristos     case 'h':
257a53f50b9Schristos     case '?':
258a53f50b9Schristos       opterrs++;
259a53f50b9Schristos     }
260a53f50b9Schristos 
261a53f50b9Schristos   /* need my pid before any dlog/plog */
262a53f50b9Schristos   am_set_mypid();
263a53f50b9Schristos #ifdef DEBUG
264a53f50b9Schristos   switch_option("debug");
265a53f50b9Schristos #endif /* DEBUG */
266a53f50b9Schristos 
267a53f50b9Schristos /*
268a53f50b9Schristos  * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
269a53f50b9Schristos  * to set the minimum cache intervals.
270a53f50b9Schristos  */
271a53f50b9Schristos #if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN)
272a53f50b9Schristos   if (!forcecache) {
273a53f50b9Schristos     fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
274a53f50b9Schristos     exit(1);
275a53f50b9Schristos   }
276a53f50b9Schristos #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) */
277a53f50b9Schristos 
278a53f50b9Schristos 
279a53f50b9Schristos   switch (argc - optind) {
280a53f50b9Schristos   case 2:
281a53f50b9Schristos     home_subdir = argv[optind + 1];
282a53f50b9Schristos   case 1:
283a53f50b9Schristos     dir_name = argv[optind];
284a53f50b9Schristos   case 0:
285a53f50b9Schristos     break;
286a53f50b9Schristos   default:
287a53f50b9Schristos     opterrs++;
288a53f50b9Schristos   }
289a53f50b9Schristos 
290a53f50b9Schristos   if (opterrs)
291a53f50b9Schristos     usage();
292a53f50b9Schristos 
293a53f50b9Schristos   /* ensure that only root can run hlfsd */
294a53f50b9Schristos   if (geteuid()) {
295a53f50b9Schristos     fprintf(stderr, "hlfsd can only be run as root\n");
296a53f50b9Schristos     exit(1);
297a53f50b9Schristos   }
298a53f50b9Schristos   setbuf(stdout, (char *) NULL);
299a53f50b9Schristos   umask(0);
300a53f50b9Schristos 
301a53f50b9Schristos   /* find gid for hlfs_group */
302a53f50b9Schristos   if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
303a53f50b9Schristos     fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
304a53f50b9Schristos 	    am_get_progname(), hlfs_group);
305a53f50b9Schristos   } else {
306a53f50b9Schristos     hlfs_gid = grp->gr_gid;
307a53f50b9Schristos   }
308a53f50b9Schristos 
309a53f50b9Schristos   /* get hostname for logging and open log before we reset umask */
310*23de60b7Schristos   if (gethostname(hostname, sizeof(hostname)) == -1) {
311*23de60b7Schristos     fprintf(stderr, "%s: gethostname failed \"%s\".\n",
312*23de60b7Schristos 	    am_get_progname(), strerror(errno));
313*23de60b7Schristos     exit(1);
314*23de60b7Schristos   }
315a53f50b9Schristos   hostname[sizeof(hostname) - 1] = '\0';
316a53f50b9Schristos   if ((dot = strchr(hostname, '.')) != NULL)
317a53f50b9Schristos     *dot = '\0';
318a53f50b9Schristos   orig_umask = umask(0);
319a53f50b9Schristos   if (logfile)
320a53f50b9Schristos     switch_to_logfile(logfile, orig_umask, 0);
321a53f50b9Schristos 
322a53f50b9Schristos #ifndef MOUNT_TABLE_ON_FILE
323a53f50b9Schristos   if (amuDebug(D_MTAB))
324a53f50b9Schristos     dlog("-D mtab option ignored");
325a53f50b9Schristos #endif /* not MOUNT_TABLE_ON_FILE */
326a53f50b9Schristos 
327a53f50b9Schristos   /* avoid hanging on other NFS servers if started elsewhere */
328a53f50b9Schristos   if (chdir("/") < 0)
329a53f50b9Schristos     fatal("cannot chdir to /: %m");
330a53f50b9Schristos 
331a53f50b9Schristos   if (geteuid() != 0)
332a53f50b9Schristos     fatal("must be root to mount filesystems");
333a53f50b9Schristos 
334a53f50b9Schristos   /*
335a53f50b9Schristos    * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
336a53f50b9Schristos    * slinkname = `basename $dir_name` - requires dir_name be writable
337a53f50b9Schristos    */
338a53f50b9Schristos 
339a53f50b9Schristos   if (dir_name[0] != '/'
340a53f50b9Schristos       || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
341a53f50b9Schristos 	  (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
342a53f50b9Schristos     if (slinkname)
343a53f50b9Schristos       *--slinkname = '/';
344a53f50b9Schristos     printf("%s: invalid mount directory/link %s\n",
345a53f50b9Schristos 	   am_get_progname(), dir_name);
346a53f50b9Schristos     exit(3);
347a53f50b9Schristos   }
348a53f50b9Schristos 
349a53f50b9Schristos   if (!forcefast) {
350a53f50b9Schristos     /* make sure mount point exists and is at least mode 555 */
351a53f50b9Schristos     if (stat(dir_name, &stmodes) < 0)
352a53f50b9Schristos       if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
353a53f50b9Schristos 	  || stat(dir_name, &stmodes) < 0)
354a53f50b9Schristos 	fatalerror(dir_name);
355a53f50b9Schristos 
356a53f50b9Schristos     if ((stmodes.st_mode & 0555) != 0555) {
357a53f50b9Schristos       fprintf(stderr, "%s: directory %s not read/executable\n",
358a53f50b9Schristos 	      am_get_progname(), dir_name);
359a53f50b9Schristos       plog(XLOG_WARNING, "directory %s not read/executable",
360a53f50b9Schristos 	   dir_name);
361a53f50b9Schristos     }
362a53f50b9Schristos 
363a53f50b9Schristos     /* warn if extraneous stuff will be hidden by mount */
364a53f50b9Schristos     if ((mountdir = opendir(dir_name)) == NULL)
365a53f50b9Schristos       fatalerror(dir_name);
366a53f50b9Schristos 
367a53f50b9Schristos     while ((direntry = readdir(mountdir)) != NULL) {
368a53f50b9Schristos       if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
369a53f50b9Schristos 	  !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
370a53f50b9Schristos 	  !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
371a53f50b9Schristos 	break;
372a53f50b9Schristos     }
373a53f50b9Schristos 
374a53f50b9Schristos     if (direntry != NULL) {
375a53f50b9Schristos       fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
376a53f50b9Schristos 	      am_get_progname(), dir_name, direntry->d_name);
377a53f50b9Schristos       plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
378a53f50b9Schristos 	   dir_name, direntry->d_name);
379a53f50b9Schristos     }
380a53f50b9Schristos     closedir(mountdir);
381a53f50b9Schristos 
382a53f50b9Schristos     /* make sure alternate spool dir exists */
383a53f50b9Schristos     if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
384a53f50b9Schristos       fprintf(stderr, "%s: cannot create alternate dir ",
385a53f50b9Schristos 	      am_get_progname());
386a53f50b9Schristos       perror(alt_spooldir);
387a53f50b9Schristos       plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
388a53f50b9Schristos 	   alt_spooldir);
389a53f50b9Schristos     }
390a53f50b9Schristos     chmod(alt_spooldir, OPEN_SPOOLMODE);
391a53f50b9Schristos 
392a53f50b9Schristos     /* create failsafe link to alternate spool directory */
393a53f50b9Schristos     *(slinkname-1) = '/';	/* unsplit dir_name to include link */
394a53f50b9Schristos     if (lstat(dir_name, &stmodes) == 0 &&
395a53f50b9Schristos 	(stmodes.st_mode & S_IFMT) != S_IFLNK) {
396a53f50b9Schristos       fprintf(stderr, "%s: failsafe %s not a symlink\n",
397a53f50b9Schristos 	      am_get_progname(), dir_name);
398a53f50b9Schristos       plog(XLOG_WARNING, "failsafe %s not a symlink\n",
399a53f50b9Schristos 	   dir_name);
400a53f50b9Schristos     } else {
401a53f50b9Schristos       unlink(dir_name);
402a53f50b9Schristos 
403a53f50b9Schristos       if (symlink(alt_spooldir, dir_name) < 0) {
404a53f50b9Schristos 	fprintf(stderr,
405a53f50b9Schristos 		"%s: cannot create failsafe symlink %s -> ",
406a53f50b9Schristos 		am_get_progname(), dir_name);
407a53f50b9Schristos 	perror(alt_spooldir);
408a53f50b9Schristos 	plog(XLOG_WARNING,
409a53f50b9Schristos 	     "cannot create failsafe symlink %s -> %s: %m",
410a53f50b9Schristos 	     dir_name, alt_spooldir);
411a53f50b9Schristos       }
412a53f50b9Schristos     }
413a53f50b9Schristos 
414a53f50b9Schristos     *(slinkname-1) = '\0';	/* resplit dir_name */
415a53f50b9Schristos   } /* end of "if (!forcefast) {" */
416a53f50b9Schristos 
417a53f50b9Schristos   /*
418a53f50b9Schristos    * Register hlfsd as an nfs service with the portmapper.
419a53f50b9Schristos    */
420*23de60b7Schristos   ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2,
421*23de60b7Schristos     NFS_VERSION);
422a53f50b9Schristos   if (ret != 0)
423a53f50b9Schristos     fatal("cannot create NFS service");
424a53f50b9Schristos 
425a53f50b9Schristos #ifdef HAVE_SIGACTION
426a53f50b9Schristos   sa.sa_handler = proceed;
427a53f50b9Schristos   sa.sa_flags = 0;
428a53f50b9Schristos   sigemptyset(&(sa.sa_mask));
429a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGUSR2);
430a53f50b9Schristos   sigaction(SIGUSR2, &sa, NULL);
431a53f50b9Schristos #else /* not HAVE_SIGACTION */
432a53f50b9Schristos   signal(SIGUSR2, proceed);
433a53f50b9Schristos #endif /* not HAVE_SIGACTION */
434a53f50b9Schristos 
435a53f50b9Schristos   plog(XLOG_INFO, "Initializing hlfsd...");
436a53f50b9Schristos   hlfsd_init();			/* start up child (forking) to run svc_run */
437a53f50b9Schristos 
438a53f50b9Schristos #ifdef HAVE_SIGACTION
439a53f50b9Schristos   sa.sa_handler = reaper;
440a53f50b9Schristos   sa.sa_flags = 0;
441a53f50b9Schristos   sigemptyset(&(sa.sa_mask));
442a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGCHLD);
443a53f50b9Schristos   sigaction(SIGCHLD, &sa, NULL);
444a53f50b9Schristos #else /* not HAVE_SIGACTION */
445a53f50b9Schristos   signal(SIGCHLD, reaper);
446a53f50b9Schristos #endif /* not HAVE_SIGACTION */
447a53f50b9Schristos 
448a53f50b9Schristos   /*
449a53f50b9Schristos    * In the parent, if -D nodaemon, we don't need to
450a53f50b9Schristos    * set this signal handler.
451a53f50b9Schristos    */
452a53f50b9Schristos   if (amuDebug(D_DAEMON)) {
453a53f50b9Schristos     while (stoplight != SIGUSR2) {
454a53f50b9Schristos       plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
455a53f50b9Schristos #ifdef HAVE_SIGSUSPEND
456a53f50b9Schristos       {
457a53f50b9Schristos 	sigset_t mask;
458a53f50b9Schristos 	sigemptyset(&mask);
459b8b2d30eSchristos 	(void)sigsuspend(&mask);	/* wait for child to set up */
460a53f50b9Schristos       }
461a53f50b9Schristos #else /* not HAVE_SIGSUSPEND */
462b8b2d30eSchristos       (void)sigpause(0);		/* wait for child to set up */
463a53f50b9Schristos #endif /* not HAVE_SIGSUSPEND */
464a53f50b9Schristos       sleep(1);
465a53f50b9Schristos     }
466a53f50b9Schristos   }
467a53f50b9Schristos 
468a53f50b9Schristos   /*
469a53f50b9Schristos    * setup options to mount table (/etc/{mtab,mnttab}) entry
470a53f50b9Schristos    */
471a53f50b9Schristos   xsnprintf(hostpid_fs, sizeof(hostpid_fs),
472a53f50b9Schristos 	    "%s:(pid%d)", hostname, masterpid);
473a53f50b9Schristos   memset((char *) &mnt, 0, sizeof(mnt));
474a53f50b9Schristos   mnt.mnt_dir = dir_name;	/* i.e., "/mail" */
475a53f50b9Schristos   mnt.mnt_fsname = hostpid_fs;
476a53f50b9Schristos   if (mntopts) {
477a53f50b9Schristos     mnt.mnt_opts = mntopts;
478a53f50b9Schristos   } else {
479a53f50b9Schristos     xstrlcpy(preopts, default_mntopts, sizeof(preopts));
480a53f50b9Schristos     /*
481a53f50b9Schristos      * Turn off all kinds of attribute and symlink caches as
482a53f50b9Schristos      * much as possible.  Also make sure that mount does not
483a53f50b9Schristos      * show up to df.
484a53f50b9Schristos      */
485a53f50b9Schristos #ifdef MNTTAB_OPT_INTR
486a53f50b9Schristos     xstrlcat(preopts, ",", sizeof(preopts));
487a53f50b9Schristos     xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
488a53f50b9Schristos #endif /* MNTTAB_OPT_INTR */
489a53f50b9Schristos #ifdef MNTTAB_OPT_IGNORE
490a53f50b9Schristos     xstrlcat(preopts, ",", sizeof(preopts));
491a53f50b9Schristos     xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
492a53f50b9Schristos #endif /* MNTTAB_OPT_IGNORE */
493a53f50b9Schristos #ifdef MNT2_GEN_OPT_CACHE
494a53f50b9Schristos     xstrlcat(preopts, ",nocache", sizeof(preopts));
495a53f50b9Schristos #endif /* MNT2_GEN_OPT_CACHE */
496a53f50b9Schristos #ifdef MNT2_NFS_OPT_SYMTTL
497a53f50b9Schristos     xstrlcat(preopts, ",symttl=0", sizeof(preopts));
498a53f50b9Schristos #endif /* MNT2_NFS_OPT_SYMTTL */
499a53f50b9Schristos     mnt.mnt_opts = preopts;
500a53f50b9Schristos   }
501a53f50b9Schristos 
502a53f50b9Schristos   /*
503a53f50b9Schristos    * Make sure that amd's top-level NFS mounts are hidden by default
504a53f50b9Schristos    * from df.
505a53f50b9Schristos    * If they don't appear to support the either the "ignore" mnttab
506a53f50b9Schristos    * option entry, or the "auto" one, set the mount type to "nfs".
507a53f50b9Schristos    */
508a53f50b9Schristos #ifdef HIDE_MOUNT_TYPE
509a53f50b9Schristos   mnt.mnt_type = HIDE_MOUNT_TYPE;
510a53f50b9Schristos #else /* not HIDE_MOUNT_TYPE */
511a53f50b9Schristos   mnt.mnt_type = "nfs";
512a53f50b9Schristos #endif /* not HIDE_MOUNT_TYPE */
513a53f50b9Schristos   /* some systems don't have a mount type, but a mount flag */
514a53f50b9Schristos 
515a53f50b9Schristos #ifndef HAVE_TRANSPORT_TYPE_TLI
516a53f50b9Schristos   amu_get_myaddress(&localsocket.sin_addr, NULL);
517a53f50b9Schristos   localsocket.sin_family = AF_INET;
518a53f50b9Schristos   localsocket.sin_port = htons(nfsxprt->xp_port);
519a53f50b9Schristos #endif /* not HAVE_TRANSPORT_TYPE_TLI */
520a53f50b9Schristos 
521a53f50b9Schristos   /*
522a53f50b9Schristos    * Update hostname field.
523a53f50b9Schristos    * Make some name prog:pid (i.e., hlfsd:174) for hostname
524a53f50b9Schristos    */
525a53f50b9Schristos   xsnprintf(progpid_fs, sizeof(progpid_fs),
526a53f50b9Schristos 	    "%s:%d", am_get_progname(), masterpid);
527a53f50b9Schristos 
528a53f50b9Schristos   /* Most kernels have a name length restriction. */
529a53f50b9Schristos   if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
530a53f50b9Schristos     xstrlcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..",
531a53f50b9Schristos 	     sizeof(progpid_fs) - MAXHOSTNAMELEN + 3);
532a53f50b9Schristos 
533a53f50b9Schristos   genflags = compute_mount_flags(&mnt);
534a53f50b9Schristos 
535a53f50b9Schristos   retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
536a53f50b9Schristos   if (retry <= 0)
537a53f50b9Schristos     retry = 1;			/* XXX */
538a53f50b9Schristos 
539a53f50b9Schristos   memmove(&anh.v2, root_fhp, sizeof(*root_fhp));
540a53f50b9Schristos #ifdef HAVE_TRANSPORT_TYPE_TLI
541a53f50b9Schristos   compute_nfs_args(&nfs_args,
542a53f50b9Schristos 		   &mnt,
543a53f50b9Schristos 		   genflags,
544a53f50b9Schristos 		   nfsncp,
545a53f50b9Schristos 		   NULL,	/* remote host IP addr is set below */
546a53f50b9Schristos 		   NFS_VERSION,	/* version 2 */
547a53f50b9Schristos 		   "udp",	/* XXX: shouldn't this be "udp"? */
548a53f50b9Schristos 		   &anh,
549a53f50b9Schristos 		   progpid_fs,	/* host name for kernel */
550a53f50b9Schristos 		   hostpid_fs); /* filesystem name for kernel */
551a53f50b9Schristos   /*
552a53f50b9Schristos    * IMPORTANT: set the correct IP address AFTERWARDS.  It cannot
553a53f50b9Schristos    * be done using the normal mechanism of compute_nfs_args(), because
554a53f50b9Schristos    * that one will allocate a new address and use NFS_SA_DREF() to copy
555a53f50b9Schristos    * parts to it, while assuming that the ip_addr passed is always
556a53f50b9Schristos    * a "struct sockaddr_in".  That assumption is incorrect on TLI systems,
557a53f50b9Schristos    * because they define a special macro HOST_SELF which is DIFFERENT
558a53f50b9Schristos    * than localhost (127.0.0.1)!
559a53f50b9Schristos    */
560a53f50b9Schristos   nfs_args.addr = &nfsxprt->xp_ltaddr;
561a53f50b9Schristos #else /* not HAVE_TRANSPORT_TYPE_TLI */
562a53f50b9Schristos   compute_nfs_args(&nfs_args,
563a53f50b9Schristos 		   &mnt,
564a53f50b9Schristos 		   genflags,
565a53f50b9Schristos 		   NULL,
566a53f50b9Schristos 		   &localsocket,
567a53f50b9Schristos 		   NFS_VERSION, /* version 2 */
568a53f50b9Schristos 		   "udp",	/* XXX: shouldn't this be "udp"? */
569a53f50b9Schristos 		   &anh,
570a53f50b9Schristos 		   progpid_fs,	/* host name for kernel */
571a53f50b9Schristos 		   hostpid_fs); /* filesystem name for kernel */
572a53f50b9Schristos #endif /* not HAVE_TRANSPORT_TYPE_TLI */
573a53f50b9Schristos 
574a53f50b9Schristos   /*************************************************************************
575a53f50b9Schristos    * NOTE: while compute_nfs_args() works ok for regular NFS mounts	   *
576a53f50b9Schristos    * the toplvl one is not, and so some options must be corrected by hand  *
577a53f50b9Schristos    * more carefully, *after* compute_nfs_args() runs.			   *
578a53f50b9Schristos    *************************************************************************/
579a53f50b9Schristos   compute_automounter_nfs_args(&nfs_args, &mnt);
580a53f50b9Schristos 
581a53f50b9Schristos /*
582a53f50b9Schristos  * For some reason, this mount may have to be done in the background, if I am
583a53f50b9Schristos  * using -D daemon.  I suspect that the actual act of mounting requires
584a53f50b9Schristos  * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
585a53f50b9Schristos  * /mail.  That means that even if you say -D daemon, at least the mount
586a53f50b9Schristos  * of hlfsd itself on top of /mail will be done in the background.
587a53f50b9Schristos  * The other alternative I have is to run svc_run, but set a special
588a53f50b9Schristos  * signal handler to perform the mount in N seconds via some alarm.
589a53f50b9Schristos  *      -Erez Zadok.
590a53f50b9Schristos  */
591a53f50b9Schristos   if (!amuDebug(D_DAEMON)) {	/* Normal case */
592a53f50b9Schristos     plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
593a53f50b9Schristos     if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0)
594a53f50b9Schristos       fatal("nfsmount: %m");
595a53f50b9Schristos   } else {			/* asked for -D daemon */
596a53f50b9Schristos     if (fork() == 0) {		/* child runs mount */
597a53f50b9Schristos       am_set_mypid();
598a53f50b9Schristos       foreground = 0;
599a53f50b9Schristos       plog(XLOG_INFO, "child NFS mounting hlfsd service points");
600a53f50b9Schristos       if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0) {
601a53f50b9Schristos 	fatal("nfsmount: %m");
602a53f50b9Schristos       }
603a53f50b9Schristos       exit(0);			/* all went well */
604a53f50b9Schristos     } else { /* fork failed or parent running */
605a53f50b9Schristos       plog(XLOG_INFO, "parent waiting 1sec for mount...");
606a53f50b9Schristos     }
607a53f50b9Schristos   }
608a53f50b9Schristos 
609a53f50b9Schristos #ifdef HAVE_TRANSPORT_TYPE_TLI
610a53f50b9Schristos   /*
611a53f50b9Schristos    * XXX: this free_knetconfig() was not done for hlfsd before,
612a53f50b9Schristos    * and apparently there was a reason for it, but why? -Erez
613a53f50b9Schristos    */
614a53f50b9Schristos   free_knetconfig(nfs_args.knconf);
615a53f50b9Schristos   /*
616a53f50b9Schristos    * local automounter mounts do not allocate a special address, so
617a53f50b9Schristos    * no need to XFREE(nfs_args.addr) under TLI.
618a53f50b9Schristos    */
619a53f50b9Schristos #endif /* HAVE_TRANSPORT_TYPE_TLI */
620a53f50b9Schristos 
621a53f50b9Schristos   if (printpid)
622a53f50b9Schristos     printf("%d\n", masterpid);
623a53f50b9Schristos 
624a53f50b9Schristos   plog(XLOG_INFO, "hlfsd ready to serve");
625a53f50b9Schristos   /*
626a53f50b9Schristos    * If asked not to fork a daemon (-D nodaemon), then hlfsd_init()
627a53f50b9Schristos    * will not run svc_run.  We must start svc_run here.
628a53f50b9Schristos    */
629a53f50b9Schristos   if (!amuDebug(D_DAEMON)) {
630a53f50b9Schristos     plog(XLOG_DEBUG, "starting no-daemon debugging svc_run");
631a53f50b9Schristos     svc_run();
632a53f50b9Schristos   }
633a53f50b9Schristos 
634a53f50b9Schristos   cleanup(0);			/* should never happen here */
635a53f50b9Schristos   return (0);			/* everything went fine? */
636a53f50b9Schristos }
637a53f50b9Schristos 
638a53f50b9Schristos 
639a53f50b9Schristos static void
hlfsd_init(void)640a53f50b9Schristos hlfsd_init(void)
641a53f50b9Schristos {
642a53f50b9Schristos   int child = 0;
643a53f50b9Schristos #ifdef HAVE_SIGACTION
644a53f50b9Schristos   struct sigaction sa;
645a53f50b9Schristos #endif /* HAVE_SIGACTION */
646a53f50b9Schristos 
647a53f50b9Schristos   /*
648a53f50b9Schristos    * Initialize file handles.
649a53f50b9Schristos    */
650a53f50b9Schristos   plog(XLOG_INFO, "initializing hlfsd file handles");
651a53f50b9Schristos   hlfsd_init_filehandles();
652a53f50b9Schristos 
653a53f50b9Schristos   /*
654a53f50b9Schristos    * If -D daemon then we must fork.
655a53f50b9Schristos    */
656a53f50b9Schristos   if (amuDebug(D_DAEMON))
657a53f50b9Schristos     child = fork();
658a53f50b9Schristos 
659a53f50b9Schristos   if (child < 0)
660a53f50b9Schristos     fatal("fork: %m");
661a53f50b9Schristos 
662a53f50b9Schristos   if (child != 0) {		/* parent process - save child pid */
663a53f50b9Schristos     masterpid = child;
664a53f50b9Schristos     am_set_mypid();		/* for logging routines */
665a53f50b9Schristos     return;
666a53f50b9Schristos   }
667a53f50b9Schristos 
668a53f50b9Schristos   /*
669a53f50b9Schristos    * CHILD CODE:
670a53f50b9Schristos    * initialize server
671a53f50b9Schristos    */
672a53f50b9Schristos 
673a53f50b9Schristos   plog(XLOG_INFO, "initializing home directory database");
674a53f50b9Schristos   plt_init();			/* initialize database */
675a53f50b9Schristos   plog(XLOG_INFO, "home directory database initialized");
676a53f50b9Schristos 
677a53f50b9Schristos   masterpid = serverpid = am_set_mypid(); /* for logging routines */
678a53f50b9Schristos 
679a53f50b9Schristos   /*
680a53f50b9Schristos    * SIGALRM/SIGHUP: reload password database if timer expired
681a53f50b9Schristos    * or user sent HUP signal.
682a53f50b9Schristos    */
683a53f50b9Schristos #ifdef HAVE_SIGACTION
684a53f50b9Schristos   sa.sa_handler = reload;
685a53f50b9Schristos   sa.sa_flags = 0;
686a53f50b9Schristos   sigemptyset(&(sa.sa_mask));
687a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGALRM);
688a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGHUP);
689a53f50b9Schristos   sigaction(SIGALRM, &sa, NULL);
690a53f50b9Schristos   sigaction(SIGHUP, &sa, NULL);
691a53f50b9Schristos #else /* not HAVE_SIGACTION */
692a53f50b9Schristos   signal(SIGALRM, reload);
693a53f50b9Schristos   signal(SIGHUP, reload);
694a53f50b9Schristos #endif /* not HAVE_SIGACTION */
695a53f50b9Schristos 
696a53f50b9Schristos   /*
697a53f50b9Schristos    * SIGTERM: cleanup and exit.
698a53f50b9Schristos    */
699a53f50b9Schristos #ifdef HAVE_SIGACTION
700a53f50b9Schristos   sa.sa_handler = cleanup;
701a53f50b9Schristos   sa.sa_flags = 0;
702a53f50b9Schristos   sigemptyset(&(sa.sa_mask));
703a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGTERM);
704a53f50b9Schristos   sigaction(SIGTERM, &sa, NULL);
705a53f50b9Schristos #else /* not HAVE_SIGACTION */
706a53f50b9Schristos   signal(SIGTERM, cleanup);
707a53f50b9Schristos #endif /* not HAVE_SIGACTION */
708a53f50b9Schristos 
709a53f50b9Schristos   /*
710a53f50b9Schristos    * SIGCHLD: interlock synchronization and testing
711a53f50b9Schristos    */
712a53f50b9Schristos #ifdef HAVE_SIGACTION
713a53f50b9Schristos   sa.sa_handler = interlock;
714a53f50b9Schristos   sa.sa_flags = 0;
715a53f50b9Schristos   sigemptyset(&(sa.sa_mask));
716a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGCHLD);
717a53f50b9Schristos   sigaction(SIGCHLD, &sa, NULL);
718a53f50b9Schristos #else /* not HAVE_SIGACTION */
719a53f50b9Schristos   signal(SIGCHLD, interlock);
720a53f50b9Schristos #endif /* not HAVE_SIGACTION */
721a53f50b9Schristos 
722a53f50b9Schristos   /*
723a53f50b9Schristos    * SIGUSR1: dump internal hlfsd maps/cache to file
724a53f50b9Schristos    */
725a53f50b9Schristos #ifdef HAVE_SIGACTION
726a53f50b9Schristos # if defined(DEBUG) || defined(DEBUG_PRINT)
727a53f50b9Schristos   sa.sa_handler = plt_print;
728a53f50b9Schristos # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
729a53f50b9Schristos   sa.sa_handler = SIG_IGN;
730a53f50b9Schristos # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
731a53f50b9Schristos   sa.sa_flags = 0;
732a53f50b9Schristos   sigemptyset(&(sa.sa_mask));
733a53f50b9Schristos   sigaddset(&(sa.sa_mask), SIGUSR1);
734a53f50b9Schristos   sigaction(SIGUSR1, &sa, NULL);
735a53f50b9Schristos #else /* not HAVE_SIGACTION */
736a53f50b9Schristos # if defined(DEBUG) || defined(DEBUG_PRINT)
737a53f50b9Schristos   signal(SIGUSR1, plt_print);
738a53f50b9Schristos # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
739a53f50b9Schristos   signal(SIGUSR1, SIG_IGN);
740a53f50b9Schristos # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
741a53f50b9Schristos #endif /* not HAVE_SIGACTION */
742a53f50b9Schristos 
743a53f50b9Schristos   if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) NULL) < 0)
744a53f50b9Schristos     fatal("setitimer: %m");
745a53f50b9Schristos 
746a53f50b9Schristos   clocktime(&startup);
747a53f50b9Schristos 
748a53f50b9Schristos   /*
749a53f50b9Schristos    * If -D daemon, then start serving here in the child,
750a53f50b9Schristos    * and the parent will exit.  But if -D nodaemon, then
751a53f50b9Schristos    * skip this code and make sure svc_run is entered elsewhere.
752a53f50b9Schristos    */
753a53f50b9Schristos   if (amuDebug(D_DAEMON)) {
754a53f50b9Schristos     /*
755a53f50b9Schristos      * Dissociate from the controlling terminal
756a53f50b9Schristos      */
757a53f50b9Schristos     amu_release_controlling_tty();
758a53f50b9Schristos 
759a53f50b9Schristos     /*
760a53f50b9Schristos      * signal parent we are ready. parent should
761a53f50b9Schristos      * mount(2) and die.
762a53f50b9Schristos      */
763a53f50b9Schristos     if (kill(getppid(), SIGUSR2) < 0)
764a53f50b9Schristos       fatal("kill: %m");
765a53f50b9Schristos     plog(XLOG_INFO, "starting svc_run");
766a53f50b9Schristos     svc_run();
767a53f50b9Schristos     cleanup(0);		/* should never happen, just in case */
768a53f50b9Schristos   }
769a53f50b9Schristos 
770a53f50b9Schristos }
771a53f50b9Schristos 
772a53f50b9Schristos 
773a53f50b9Schristos static RETSIGTYPE
proceed(int signum)774a53f50b9Schristos proceed(int signum)
775a53f50b9Schristos {
776a53f50b9Schristos   stoplight = signum;
777a53f50b9Schristos }
778a53f50b9Schristos 
779a53f50b9Schristos 
780a53f50b9Schristos static RETSIGTYPE
reload(int signum)781a53f50b9Schristos reload(int signum)
782a53f50b9Schristos {
783a53f50b9Schristos   int child;
784a53f50b9Schristos   int status;
785a53f50b9Schristos 
786a53f50b9Schristos   if (getpid() != masterpid)
787a53f50b9Schristos     return;
788a53f50b9Schristos 
789a53f50b9Schristos   /*
790a53f50b9Schristos    * If received a SIGHUP, close and reopen the log file (so that it
791a53f50b9Schristos    * can be rotated)
792a53f50b9Schristos    */
793a53f50b9Schristos   if (signum == SIGHUP && logfile)
794a53f50b9Schristos     switch_to_logfile(logfile, orig_umask, 0);
795a53f50b9Schristos 
796a53f50b9Schristos   /*
797a53f50b9Schristos    * parent performs the reload, while the child continues to serve
798a53f50b9Schristos    * clients accessing the home dir link.
799a53f50b9Schristos    */
800a53f50b9Schristos   if ((child = fork()) > 0) {
801a53f50b9Schristos     serverpid = child;		/* parent runs here */
802a53f50b9Schristos     am_set_mypid();
803a53f50b9Schristos 
804a53f50b9Schristos     plt_init();
805a53f50b9Schristos 
806a53f50b9Schristos     if (kill(child, SIGKILL) < 0) {
807a53f50b9Schristos       plog(XLOG_ERROR, "kill child: %m");
808a53f50b9Schristos     } else {			/* wait for child to die before continue */
809a53f50b9Schristos       if (wait(&status) != child) {
810a53f50b9Schristos 	/*
811a53f50b9Schristos 	 * I took out this line because it generates annoying output.  It
812a53f50b9Schristos 	 * indicates a very small bug in hlfsd which is totally harmless.
813a53f50b9Schristos 	 * It causes hlfsd to work a bit harder than it should.
814a53f50b9Schristos 	 * Nevertheless, I intend on fixing it in a future release.
815a53f50b9Schristos 	 * -Erez Zadok <ezk@cs.columbia.edu>
816a53f50b9Schristos 	 */
817a53f50b9Schristos 	/* plog(XLOG_ERROR, "unknown child"); */
818a53f50b9Schristos       }
819a53f50b9Schristos     }
820a53f50b9Schristos     serverpid = masterpid;
821a53f50b9Schristos   } else if (child < 0) {
822a53f50b9Schristos     plog(XLOG_ERROR, "unable to fork: %m");
823a53f50b9Schristos   } else {
824a53f50b9Schristos     /* let child handle requests while we reload */
825a53f50b9Schristos     serverpid = getpid();
826a53f50b9Schristos     am_set_mypid();
827a53f50b9Schristos   }
828a53f50b9Schristos }
829a53f50b9Schristos 
830a53f50b9Schristos 
831a53f50b9Schristos RETSIGTYPE
cleanup(int signum)832a53f50b9Schristos cleanup(int signum)
833a53f50b9Schristos {
834a53f50b9Schristos   struct stat stbuf;
835a53f50b9Schristos   int umount_result;
836a53f50b9Schristos 
837a53f50b9Schristos   if (amuDebug(D_DAEMON)) {
838a53f50b9Schristos     if (getpid() != masterpid)
839a53f50b9Schristos       return;
840a53f50b9Schristos 
841a53f50b9Schristos     if (fork() != 0) {
842a53f50b9Schristos       masterpid = 0;
843a53f50b9Schristos       am_set_mypid();
844a53f50b9Schristos       return;
845a53f50b9Schristos     }
846a53f50b9Schristos   }
847a53f50b9Schristos   am_set_mypid();
848a53f50b9Schristos 
849a53f50b9Schristos   for (;;) {
850a53f50b9Schristos     while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name, 0)) == EBUSY) {
851a53f50b9Schristos       dlog("cleanup(): umount delaying for 10 seconds");
852a53f50b9Schristos       sleep(10);
853a53f50b9Schristos     }
854a53f50b9Schristos     if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
855a53f50b9Schristos       plog(XLOG_ERROR, "unable to unmount %s", dir_name);
856a53f50b9Schristos       plog(XLOG_ERROR, "suspending, unmount before terminating");
857a53f50b9Schristos       kill(am_mypid, SIGSTOP);
858a53f50b9Schristos       continue;			/* retry unmount */
859a53f50b9Schristos     }
860a53f50b9Schristos     break;
861a53f50b9Schristos   }
862a53f50b9Schristos 
863a53f50b9Schristos   if (amuDebug(D_DAEMON)) {
864a53f50b9Schristos     plog(XLOG_INFO, "cleanup(): killing processes and terminating");
865a53f50b9Schristos     kill(masterpid, SIGKILL);
866a53f50b9Schristos     kill(serverpid, SIGKILL);
867a53f50b9Schristos   }
868a53f50b9Schristos 
869a53f50b9Schristos   plog(XLOG_INFO, "hlfsd terminating with status 0\n");
870a53f50b9Schristos   _exit(0);
871a53f50b9Schristos }
872a53f50b9Schristos 
873a53f50b9Schristos 
874a53f50b9Schristos static RETSIGTYPE
reaper(int signum)875a53f50b9Schristos reaper(int signum)
876a53f50b9Schristos {
877a53f50b9Schristos   int result;
878a53f50b9Schristos 
879a53f50b9Schristos   if (wait(&result) == masterpid) {
880a53f50b9Schristos     _exit(4);
881a53f50b9Schristos   }
882a53f50b9Schristos }
883a53f50b9Schristos 
884a53f50b9Schristos 
885a53f50b9Schristos void
hlfsd_going_down(int rc)886a53f50b9Schristos hlfsd_going_down(int rc)
887a53f50b9Schristos {
888a53f50b9Schristos   int mypid = getpid();		/* XXX: should this be the global am_mypid */
889a53f50b9Schristos 
890a53f50b9Schristos   if (mypid == masterpid)
891a53f50b9Schristos     cleanup(0);
892a53f50b9Schristos   else if (mypid == serverpid)
893a53f50b9Schristos     kill(masterpid, SIGTERM);
894a53f50b9Schristos 
895a53f50b9Schristos   exit(rc);
896a53f50b9Schristos }
897a53f50b9Schristos 
898a53f50b9Schristos 
899a53f50b9Schristos void
fatal(char * mess)900a53f50b9Schristos fatal(char *mess)
901a53f50b9Schristos {
902a53f50b9Schristos   if (logfile && !STREQ(logfile, "stderr")) {
903a53f50b9Schristos     char lessmess[128];
904a53f50b9Schristos     int messlen;
905a53f50b9Schristos 
906a53f50b9Schristos     messlen = strlen(mess);
907a53f50b9Schristos 
908a53f50b9Schristos     if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
909a53f50b9Schristos       fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
910a53f50b9Schristos     else {
911a53f50b9Schristos       xstrlcpy(lessmess, mess, sizeof(lessmess));
912a53f50b9Schristos       lessmess[messlen - 4] = '\0';
913a53f50b9Schristos 
914a53f50b9Schristos       fprintf(stderr, "%s: %s: %s\n",
915a53f50b9Schristos 	      am_get_progname(), lessmess, strerror(errno));
916a53f50b9Schristos     }
917a53f50b9Schristos   }
918a53f50b9Schristos   plog(XLOG_FATAL, "%s", mess);
919a53f50b9Schristos 
920a53f50b9Schristos   hlfsd_going_down(1);
921a53f50b9Schristos }
922