xref: /openbsd-src/usr.sbin/amd/amd/amd.c (revision c0c90351672c5fc26a45cc4e1c51ee3b16e9c570)
1 /*
2  * Copyright (c) 1989 Jan-Simon Pendry
3  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Jan-Simon Pendry at Imperial College, London.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	from: @(#)amd.c	8.1 (Berkeley) 6/6/93
35  *	$Id: amd.c,v 1.25 2023/07/05 18:45:14 guenther Exp $
36  */
37 
38 /*
39  * Automounter
40  */
41 
42 #include "am.h"
43 #include <signal.h>
44 #include <sys/ioctl.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <setjmp.h>
49 #include <endian.h>
50 
51 #include <rpc/rpc.h>
52 #include <rpcsvc/ypclnt.h>
53 #include <rpcsvc/yp_prot.h>
54 
55 #if BYTE_ORDER == LITTLE_ENDIAN
56 #define ARCH_ENDIAN "little"
57 #elif BYTE_ORDER == BIG_ENDIAN
58 #define ARCH_ENDIAN "big"
59 #else
60 #error "unknown endian"
61 #endif
62 
63 char pid_fsname[16 + HOST_NAME_MAX+1];	/* "kiska.southseas.nz:(pid%d)" */
64 #ifdef HAS_HOST
65 #ifdef HOST_EXEC
66 char *host_helper;
67 #endif /* HOST_EXEC */
68 #endif /* HAS_HOST */
69 char *auto_dir = "/tmp_mnt";
70 char *hostdomain = "unknown.domain";
71 char hostname[HOST_NAME_MAX+1] = "localhost"; /* Hostname */
72 char hostd[2*(HOST_NAME_MAX+1)];	/* Host+domain */
73 char *op_sys = "bsd44";			/* Name of current op_sys */
74 char *arch = ARCH_REP;			/* Name of current architecture */
75 char *endian = ARCH_ENDIAN;		/* Big or Little endian */
76 char *wire;
77 int foreground = 1;			/* This is the top-level server */
78 pid_t mypid;				/* Current process id */
79 volatile sig_atomic_t immediate_abort;	/* Should close-down unmounts be retried */
80 struct in_addr myipaddr;		/* (An) IP address of this host */
81 serv_state amd_state;
82 struct amd_stats amd_stats;		/* Server statistics */
83 time_t do_mapc_reload = 0;		/* mapc_reload() call required? */
84 jmp_buf select_intr;
85 int select_intr_valid;
86 int orig_umask;
87 
88 /*
89  * Signal handler:
90  * SIGINT - tells amd to do a full shutdown, including unmounting all filesystem.
91  * SIGTERM - tells amd to shutdown now.  Just unmounts the automount nodes.
92  */
93 static void
sigterm(int sig)94 sigterm(int sig)
95 {
96 
97 	switch (sig) {
98 	case SIGINT:
99 		immediate_abort = 15;
100 		break;
101 
102 	case SIGTERM:
103 		immediate_abort = -1;
104 		/* fall through... */
105 
106 	default:
107 		plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
108 		break;
109 	}
110 	if (select_intr_valid)
111 		longjmp(select_intr, sig);
112 }
113 
114 /*
115  * Hook for cache reload.
116  * When a SIGHUP arrives it schedules a call to mapc_reload
117  */
118 static void
sighup(int sig)119 sighup(int sig)
120 {
121 
122 #ifdef DEBUG
123 	if (sig != SIGHUP)
124 		dlog("spurious call to sighup");
125 #endif /* DEBUG */
126 	/*
127 	 * Force a reload by zero'ing the timer
128 	 */
129 	if (amd_state == Run)
130 		do_mapc_reload = 0;
131 }
132 
133 static void
parent_exit(int sig)134 parent_exit(int sig)
135 {
136 	_exit(0);
137 }
138 
139 static pid_t
daemon_mode(void)140 daemon_mode(void)
141 {
142 	pid_t bgpid;
143 
144 	signal(SIGQUIT, parent_exit);
145 	bgpid = background();
146 
147 	if (bgpid != 0) {
148 		if (print_pid) {
149 			printf("%ld\n", (long)bgpid);
150 			fflush(stdout);
151 		}
152 		/*
153 		 * Now wait for the automount points to
154 		 * complete.
155 		 */
156 		for (;;)
157 			pause();
158 	}
159 
160 	signal(SIGQUIT, SIG_DFL);
161 
162 	/*
163 	 * Pretend we are in the foreground again
164 	 */
165 	foreground = 1;
166 
167 #ifdef TIOCNOTTY
168 	{
169 		int t = open("/dev/tty", O_RDWR);
170 		if (t == -1) {
171 			if (errno != ENXIO)	/* not an error if already no controlling tty */
172 				plog(XLOG_WARNING, "Could not open controlling tty: %m");
173 		} else {
174 			if (ioctl(t, TIOCNOTTY, 0) == -1 && errno != ENOTTY)
175 				plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m");
176 			(void) close(t);
177 		}
178 	}
179 #else
180 	(void) setpgrp();
181 #endif /* TIOCNOTTY */
182 
183 	return getppid();
184 }
185 
186 int
main(int argc,char * argv[])187 main(int argc, char *argv[])
188 {
189 	char *domdot;
190 	pid_t ppid = 0;
191 	int error;
192 
193 	logfp = stderr;		/* Log errors to stderr initially */
194 
195 	/*
196 	 * Make sure some built-in assumptions are true before we start
197 	 */
198 	assert(sizeof(nfscookie) >= sizeof (unsigned int));
199 	assert(sizeof(int) >= 4);
200 
201 	/*
202 	 * Set processing status.
203 	 */
204 	amd_state = Start;
205 
206 	/*
207 	 * Initialise process id.  This is kept
208 	 * cached since it is used for generating
209 	 * and using file handles.
210 	 */
211 	mypid = getpid();
212 
213 	/*
214 	 * Get local machine name
215 	 */
216 	if (gethostname(hostname, sizeof(hostname)) == -1) {
217 		plog(XLOG_FATAL, "gethostname: %m");
218 		going_down(1);
219 	}
220 	/*
221 	 * Check it makes sense
222 	 */
223 	if (!*hostname) {
224 		plog(XLOG_FATAL, "host name is not set");
225 		going_down(1);
226 	}
227 	/*
228 	 * Partially initialise hostd[].  This
229 	 * is completed in get_args().
230 	 */
231 	if ((domdot = strchr(hostname, '.'))) {
232 		/*
233 		 * Hostname already contains domainname.
234 		 * Split out hostname and domainname
235 		 * components
236 		 */
237 		*domdot++ = '\0';
238 		hostdomain = domdot;
239 	}
240 	strlcpy(hostd, hostname, sizeof hostd);
241 
242 	/*
243 	 * Trap interrupts for shutdowns.
244 	 */
245 	(void) signal(SIGINT, sigterm);
246 
247 	/*
248 	 * Hangups tell us to reload the cache
249 	 */
250 	(void) signal(SIGHUP, sighup);
251 
252 	/*
253 	 * Trap Terminate so that we can shutdown gracefully (some chance)
254 	 */
255 	(void) signal(SIGTERM, sigterm);
256 	/*
257 	 * Trap Death-of-a-child.  These allow us to
258 	 * pick up the exit status of backgrounded mounts.
259 	 * See "sched.c".
260 	 */
261 	(void) signal(SIGCHLD, sigchld);
262 
263 	/*
264 	 * Fix-up any umask problems.  Most systems default
265 	 * to 002 which is not too convenient for our purposes
266 	 */
267 	orig_umask = umask(0);
268 
269 	/*
270 	 * Figure out primary network name
271 	 */
272 	wire = getwire();
273 
274 	/*
275 	 * Determine command-line arguments
276 	 */
277 	get_args(argc, argv);
278 
279 	if (mkdir(auto_dir, 0755) == -1) {
280 		if (errno != EEXIST)
281 			plog(XLOG_FATAL, "mkdir(autodir = %s: %m", auto_dir);
282 	}
283 
284 	/*
285 	 * Get our own IP address so that we
286 	 * can mount the automounter.
287 	 */
288 	{ struct sockaddr_in sin;
289 	  get_myaddress(&sin);
290 	  myipaddr.s_addr = sin.sin_addr.s_addr;
291 	}
292 
293 	/*
294 	 * Now check we are root.
295 	 */
296 	if (geteuid() != 0) {
297 		plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %u)", geteuid());
298 		going_down(1);
299 	}
300 
301 	/*
302 	 * If the domain was specified then bind it here
303 	 * to circumvent any default bindings that may
304 	 * be done in the C library.
305 	 */
306 	if (domain && yp_bind(domain)) {
307 		plog(XLOG_FATAL, "Can't bind to domain \"%s\"", domain);
308 		going_down(1);
309 	}
310 
311 #ifdef DEBUG
312 	Debug(D_DAEMON)
313 #endif /* DEBUG */
314 	ppid = daemon_mode();
315 
316 	snprintf(pid_fsname, sizeof(pid_fsname), "%s:(pid%ld)", hostname, (long)mypid);
317 
318 	do_mapc_reload = clocktime() + ONE_HOUR;
319 
320 	/*
321 	 * Register automounter with system
322 	 */
323 	error = mount_automounter(ppid);
324 	if (error && ppid)
325 		kill(ppid, SIGALRM);
326 	going_down(error);
327 
328 	abort();
329 }
330