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