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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34char copyright[] = 35"@(#) Copyright (c) 1992, 1993, 1994\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /* not lint */ 38 39#if 0 40static char sccsid[] = "@(#)mount_portal.c 8.6 (Berkeley) 4/26/95"; 41#endif 42 43#include <sys/cdefs.h> 44__FBSDID("$FreeBSD$"); 45 46#include <sys/param.h> 47#include <sys/wait.h> 48#include <sys/socket.h> 49#include <sys/un.h> 50#include <sys/stat.h> 51#include <sys/syslog.h> 52#include <sys/mount.h> 53 54#include <err.h> 55#include <errno.h> 56#include <stdio.h> 57#include <stdlib.h> 58#include <string.h> 59#include <sysexits.h> 60#include <unistd.h> 61 62#include "mntopts.h" 63#include "pathnames.h" 64#include "portald.h" 65 66struct mntopt mopts[] = { 67 MOPT_STDOPTS, 68 MOPT_END 69}; 70 71static void usage(void) __dead2; 72 73static volatile sig_atomic_t readcf; /* Set when SIGHUP received */ 74 75static void sighup(int sig __unused) 76{ 77 readcf ++; 78} 79 80static void sigchld(int sig __unused) 81{ 82 pid_t pid; 83 84 while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0) 85 ; 86 /* wrtp - waitpid _doesn't_ return 0 when no children! */ 87#ifdef notdef 88 if (pid < 0 && errno != ECHILD) 89 syslog(LOG_WARNING, "waitpid: %s", strerror(errno)); 90#endif 91} 92 93int 94main(int argc, char *argv[]) 95{ 96 struct portal_args args; 97 struct sockaddr_un un; 98 char *conf; 99 char mountpt[MAXPATHLEN]; 100 int mntflags = 0; 101 char tag[32]; 102 mode_t um; 103 104 qelem q; 105 int rc; 106 int so; 107 int error = 0; 108 109 /* 110 * Crack command line args 111 */ 112 int ch; 113 114 while ((ch = getopt(argc, argv, "o:")) != -1) { 115 switch (ch) { 116 case 'o': 117 getmntopts(optarg, mopts, &mntflags, 0); 118 break; 119 default: 120 error = 1; 121 break; 122 } 123 } 124 125 if (optind != (argc - 2)) 126 error = 1; 127 128 if (error) 129 usage(); 130 131 /* 132 * Get config file and mount point 133 */ 134 conf = argv[optind]; 135 if (conf[0] != '/') { 136 (void)fprintf(stderr, 137 "The configuration file must be specified" 138 "through an absolute file path.\n"); 139 exit(EX_USAGE); 140 } 141 142 /* resolve the mountpoint with realpath(3) */ 143 (void)checkpath(argv[optind+1], mountpt); 144 145 /* 146 * Construct the listening socket 147 */ 148 un.sun_family = AF_UNIX; 149 if (sizeof(_PATH_TMPPORTAL) >= sizeof(un.sun_path)) { 150 errx(EX_SOFTWARE, "portal socket name too long"); 151 } 152 strcpy(un.sun_path, _PATH_TMPPORTAL); 153 mktemp(un.sun_path); 154 un.sun_len = strlen(un.sun_path); 155 156 so = socket(AF_UNIX, SOCK_STREAM, 0); 157 if (so < 0) { 158 err(EX_OSERR, "socket"); 159 } 160 um = umask(077); 161 (void) unlink(un.sun_path); 162 if (bind(so, (struct sockaddr *) &un, sizeof(un)) < 0) 163 err(1, NULL); 164 165 (void) unlink(un.sun_path); 166 (void) umask(um); 167 168 (void) listen(so, 5); 169 170 args.pa_socket = so; 171 sprintf(tag, "portal:%d", getpid()); 172 args.pa_config = tag; 173 174 rc = mount("portalfs", mountpt, mntflags, &args); 175 if (rc < 0) 176 err(1, NULL); 177 178 /* 179 * Everything is ready to go - now is a good time to fork 180 */ 181#ifndef DEBUG 182 daemon(0, 0); 183#endif 184 185 /* 186 * Start logging (and change name) 187 */ 188 openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON); 189 190 q.q_forw = q.q_back = &q; 191 readcf = 1; 192 193 signal(SIGCHLD, sigchld); 194 signal(SIGHUP, sighup); 195 196 /* 197 * Just loop waiting for new connections and activating them 198 */ 199 for (;;) { 200 struct sockaddr_un un2; 201 int len2 = sizeof(un2); 202 int so2; 203 pid_t pid; 204 fd_set fdset; 205 206 /* 207 * Check whether we need to re-read the configuration file 208 */ 209 if (readcf) { 210#ifdef DEBUG 211 printf ("re-reading configuration file\n"); 212#endif 213 readcf = 0; 214 conf_read(&q, conf); 215 continue; 216 } 217 218 /* 219 * Accept a new connection 220 * Will get EINTR if a signal has arrived, so just 221 * ignore that error code 222 */ 223 FD_ZERO(&fdset); 224 FD_SET(so, &fdset); 225 rc = select(so+1, &fdset, (fd_set *) 0, (fd_set *) 0, (struct timeval *) 0); 226 if (rc < 0) { 227 if (errno == EINTR) 228 continue; 229 syslog(LOG_ERR, "select: %s", strerror(errno)); 230 exit(EX_OSERR); 231 } 232 if (rc == 0) 233 break; 234 so2 = accept(so, (struct sockaddr *) &un2, &len2); 235 if (so2 < 0) { 236 /* 237 * The unmount function does a shutdown on the socket 238 * which will generated ECONNABORTED on the accept. 239 */ 240 if (errno == ECONNABORTED) 241 break; 242 if (errno != EINTR) { 243 syslog(LOG_ERR, "accept: %s", strerror(errno)); 244 exit(EX_OSERR); 245 } 246 continue; 247 } 248 249 /* 250 * Now fork a new child to deal with the connection 251 */ 252 eagain:; 253 switch (pid = fork()) { 254 case -1: 255 if (errno == EAGAIN) { 256 sleep(1); 257 goto eagain; 258 } 259 syslog(LOG_ERR, "fork: %s", strerror(errno)); 260 break; 261 case 0: 262 (void) close(so); 263 activate(&q, so2); 264 exit(0); 265 default: 266 (void) close(so2); 267 break; 268 } 269 } 270 syslog(LOG_INFO, "%s unmounted", mountpt); 271 exit(0); 272} 273 274static void 275usage(void) 276{ 277 (void)fprintf(stderr, 278 "usage: mount_portalfs [-o options] config mount-point\n"); 279 exit(EX_USAGE); 280} 281