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