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