1 /*
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1992, 1993, 1994\n\
14 	The Regents of the University of California.  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)mount_portal.c	8.4 (Berkeley) 03/27/94";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/wait.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/syslog.h>
26 #include <sys/mount.h>
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "mntopts.h"
37 #include "pathnames.h"
38 #include "portald.h"
39 
40 struct mntopt mopts[] = {
41 	MOPT_STDOPTS,
42 	{ NULL }
43 };
44 
45 static void usage __P((void));
46 
47 static sig_atomic_t readcf;	/* Set when SIGHUP received */
48 
49 static void sigchld(sig)
50 int sig;
51 {
52 	pid_t pid;
53 
54 	while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0)
55 		;
56 	if (pid < 0)
57 		syslog(LOG_WARNING, "waitpid: %s", strerror(errno));
58 }
59 
60 int
61 main(argc, argv)
62 	int argc;
63 	char *argv[];
64 {
65 	struct portal_args args;
66 	struct sockaddr_un un;
67 	char *conf;
68 	char *mountpt;
69 	int mntflags = 0;
70 	char tag[32];
71 
72 	qelem q;
73 	int rc;
74 	int so;
75 	int error = 0;
76 
77 	/*
78 	 * Crack command line args
79 	 */
80 	int ch;
81 
82 	while ((ch = getopt(argc, argv, "o:")) != EOF) {
83 		switch (ch) {
84 		case 'o':
85 			getmntopts(optarg, mopts, &mntflags);
86 			break;
87 		default:
88 			error = 1;
89 			break;
90 		}
91 	}
92 
93 	if (optind != (argc - 2))
94 		error = 1;
95 
96 	if (error)
97 		usage();
98 
99 	/*
100 	 * Get config file and mount point
101 	 */
102 	conf = argv[optind];
103 	mountpt = argv[optind+1];
104 
105 	/*
106 	 * Construct the listening socket
107 	 */
108 	un.sun_family = AF_UNIX;
109 	if (sizeof(_PATH_TMPPORTAL) >= sizeof(un.sun_path)) {
110 		fprintf(stderr, "mount_portal: portal socket name too long\n");
111 		exit(1);
112 	}
113 	strcpy(un.sun_path, _PATH_TMPPORTAL);
114 	mktemp(un.sun_path);
115 	un.sun_len = strlen(un.sun_path);
116 
117 	so = socket(AF_UNIX, SOCK_STREAM, 0);
118 	if (so < 0) {
119 		fprintf(stderr, "mount_portal: socket: %s\n", strerror(errno));
120 		exit(1);
121 	}
122 	(void) unlink(un.sun_path);
123 	if (bind(so, (struct sockaddr *) &un, sizeof(un)) < 0)
124 		err(1, NULL);
125 	(void) unlink(un.sun_path);
126 
127 	(void) listen(so, 5);
128 
129 	args.pa_socket = so;
130 	sprintf(tag, "portal:%d", getpid());
131 	args.pa_config = tag;
132 
133 	rc = mount(MOUNT_PORTAL, mountpt, mntflags, &args);
134 	if (rc < 0)
135 		err(1, NULL);
136 
137 #ifdef notdef
138 	/*
139 	 * Everything is ready to go - now is a good time to fork
140 	 */
141 	daemon(0, 0);
142 #endif
143 
144 	/*
145 	 * Start logging (and change name)
146 	 */
147 	openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON);
148 
149 	q.q_forw = q.q_back = &q;
150 	readcf = 1;
151 
152 	signal(SIGCHLD, sigchld);
153 
154 	/*
155 	 * Just loop waiting for new connections and activating them
156 	 */
157 	for (;;) {
158 		struct sockaddr_un un2;
159 		int len2 = sizeof(un2);
160 		int so2;
161 		pid_t pid;
162 		fd_set fdset;
163 		int rc;
164 
165 		/*
166 		 * Check whether we need to re-read the configuration file
167 		 */
168 		if (readcf) {
169 			readcf = 0;
170 			conf_read(&q, conf);
171 			continue;
172 		}
173 
174 		/*
175 		 * Accept a new connection
176 		 * Will get EINTR if a signal has arrived, so just
177 		 * ignore that error code
178 		 */
179 		FD_SET(so, &fdset);
180 		rc = select(so+1, &fdset, (void *) 0, (void *) 0, (void *) 0);
181 		if (rc < 0) {
182 			if (errno == EINTR)
183 				continue;
184 			syslog(LOG_ERR, "select: %s", strerror(errno));
185 			exit(1);
186 		}
187 		if (rc == 0)
188 			break;
189 		so2 = accept(so, (struct sockaddr *) &un2, &len2);
190 		if (so2 < 0) {
191 			/*
192 			 * The unmount function does a shutdown on the socket
193 			 * which will generated ECONNABORTED on the accept.
194 			 */
195 			if (errno == ECONNABORTED)
196 				break;
197 			if (errno != EINTR) {
198 				syslog(LOG_ERR, "accept: %s", strerror(errno));
199 				exit(1);
200 			}
201 			continue;
202 		}
203 
204 		/*
205 		 * Now fork a new child to deal with the connection
206 		 */
207 	eagain:;
208 		switch (pid = fork()) {
209 		case -1:
210 			if (errno == EAGAIN) {
211 				sleep(1);
212 				goto eagain;
213 			}
214 			syslog(LOG_ERR, "fork: %s", strerror(errno));
215 			break;
216 		case 0:
217 			(void) close(so);
218 			activate(&q, so2);
219 			break;
220 		default:
221 			(void) close(so2);
222 			break;
223 		}
224 	}
225 	syslog(LOG_INFO, "%s unmounted", mountpt);
226 	exit(0);
227 }
228 
229 static void
230 usage()
231 {
232 	(void)fprintf(stderr,
233 		"usage: mount_portal [-o options] config mount-point\n");
234 	exit(1);
235 }
236