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.5 (Berkeley) 06/14/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 && errno != ECHILD) 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 /* 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 228 usage() 229 { 230 (void)fprintf(stderr, 231 "usage: mount_portal [-o options] config mount-point\n"); 232 exit(1); 233 } 234