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.6 (Berkeley) 04/26/95";
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
sigchld(sig)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 && errno != ECHILD)
57 syslog(LOG_WARNING, "waitpid: %s", strerror(errno));
58 }
59
60 int
main(argc,argv)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, 0);
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("portal", mountpt, mntflags, &args);
134 if (rc < 0)
135 err(1, NULL);
136
137 /*
138 * Everything is ready to go - now is a good time to fork
139 */
140 daemon(0, 0);
141
142 /*
143 * Start logging (and change name)
144 */
145 openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON);
146
147 q.q_forw = q.q_back = &q;
148 readcf = 1;
149
150 signal(SIGCHLD, sigchld);
151
152 /*
153 * Just loop waiting for new connections and activating them
154 */
155 for (;;) {
156 struct sockaddr_un un2;
157 int len2 = sizeof(un2);
158 int so2;
159 pid_t pid;
160 fd_set fdset;
161 int rc;
162
163 /*
164 * Check whether we need to re-read the configuration file
165 */
166 if (readcf) {
167 readcf = 0;
168 conf_read(&q, conf);
169 continue;
170 }
171
172 /*
173 * Accept a new connection
174 * Will get EINTR if a signal has arrived, so just
175 * ignore that error code
176 */
177 FD_SET(so, &fdset);
178 rc = select(so+1, &fdset, (void *) 0, (void *) 0, (void *) 0);
179 if (rc < 0) {
180 if (errno == EINTR)
181 continue;
182 syslog(LOG_ERR, "select: %s", strerror(errno));
183 exit(1);
184 }
185 if (rc == 0)
186 break;
187 so2 = accept(so, (struct sockaddr *) &un2, &len2);
188 if (so2 < 0) {
189 /*
190 * The unmount function does a shutdown on the socket
191 * which will generated ECONNABORTED on the accept.
192 */
193 if (errno == ECONNABORTED)
194 break;
195 if (errno != EINTR) {
196 syslog(LOG_ERR, "accept: %s", strerror(errno));
197 exit(1);
198 }
199 continue;
200 }
201
202 /*
203 * Now fork a new child to deal with the connection
204 */
205 eagain:;
206 switch (pid = fork()) {
207 case -1:
208 if (errno == EAGAIN) {
209 sleep(1);
210 goto eagain;
211 }
212 syslog(LOG_ERR, "fork: %s", strerror(errno));
213 break;
214 case 0:
215 (void) close(so);
216 activate(&q, so2);
217 exit(0);
218 default:
219 (void) close(so2);
220 break;
221 }
222 }
223 syslog(LOG_INFO, "%s unmounted", mountpt);
224 exit(0);
225 }
226
227 static void
usage()228 usage()
229 {
230 (void)fprintf(stderr,
231 "usage: mount_portal [-o options] config mount-point\n");
232 exit(1);
233 }
234