1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1989 Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif not lint 16 17 #ifndef lint 18 static char sccsid[] = "@(#)nfsd.c 5.10 (Berkeley) 04/24/91"; 19 #endif not lint 20 21 #include <sys/types.h> 22 #include <sys/signal.h> 23 #include <sys/ioctl.h> 24 #include <sys/stat.h> 25 #include <sys/wait.h> 26 #include <sys/mount.h> 27 #include <sys/socket.h> 28 #include <sys/socketvar.h> 29 #include <stdio.h> 30 #include <syslog.h> 31 #include <fcntl.h> 32 #include <string.h> 33 #include <netdb.h> 34 #include <rpc/rpc.h> 35 #include <rpc/pmap_clnt.h> 36 #include <rpc/pmap_prot.h> 37 #include <nfs/rpcv2.h> 38 #include <nfs/nfsv2.h> 39 40 /* Global defs */ 41 #ifdef DEBUG 42 #define syslog(e, s) fprintf(stderr,(s)) 43 int debug = 1; 44 #else 45 int debug = 0; 46 #endif 47 struct hadr { 48 u_long ha_sad; 49 struct hadr *ha_next; 50 }; 51 struct hadr hphead; 52 char **Argv = NULL; /* pointer to argument vector */ 53 char *LastArg = NULL; /* end of argv */ 54 void reapchild(); 55 56 /* 57 * Nfs server daemon mostly just a user context for nfssvc() 58 * 1 - do file descriptor and signal cleanup 59 * 2 - create server socket 60 * 3 - register socket with portmap 61 * For SOCK_DGRAM, just fork children and send them into the kernel 62 * by calling nfssvc() 63 * For connection based sockets, loop doing accepts. When you get a new socket 64 * from accept, fork a child that drops into the kernel via. nfssvc. 65 * This child will return from nfssvc when the connection is closed, so 66 * just shutdown() and exit(). 67 * The arguments are: 68 * -t - support tcp nfs clients 69 * -u - support udp nfs clients 70 */ 71 main(argc, argv, envp) 72 int argc; 73 char *argv[], *envp[]; 74 { 75 register int i; 76 register char *cp, *cp2; 77 register struct hadr *hp; 78 int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len; 79 int reregister = 0; 80 char opt; 81 extern int optind; 82 extern char *optarg; 83 struct sockaddr_in saddr, msk, mtch, peername; 84 85 86 /* 87 * Save start and extent of argv for setproctitle. 88 */ 89 90 Argv = argv; 91 if (envp == 0 || *envp == 0) 92 envp = argv; 93 while (*envp) 94 envp++; 95 LastArg = envp[-1] + strlen(envp[-1]); 96 while ((opt = getopt(argc, argv, "rt:u:")) != EOF) 97 switch (opt) { 98 case 'r': 99 reregister++; 100 break; 101 case 't': 102 tcpflag++; 103 if (cp = index(optarg, ',')) { 104 *cp++ = '\0'; 105 msk.sin_addr.s_addr = inet_addr(optarg); 106 if (msk.sin_addr.s_addr == -1) 107 usage(); 108 if (cp2 = index(cp, ',')) 109 *cp2++ = '\0'; 110 mtch.sin_addr.s_addr = inet_addr(cp); 111 if (mtch.sin_addr.s_addr == -1) 112 usage(); 113 cp = cp2; 114 hphead.ha_next = (struct hadr *)0; 115 while (cp) { 116 if (cp2 = index(cp, ',')) 117 *cp2++ = '\0'; 118 hp = (struct hadr *) 119 malloc(sizeof (struct hadr)); 120 hp->ha_sad = inet_addr(cp); 121 if (hp->ha_sad == -1) 122 usage(); 123 hp->ha_next = hphead.ha_next; 124 hphead.ha_next = hp; 125 cp = cp2; 126 } 127 } else 128 usage(); 129 break; 130 case 'u': 131 udpflag++; 132 if (cp = index(optarg, ',')) { 133 *cp++ = '\0'; 134 msk.sin_addr.s_addr = inet_addr(optarg); 135 if (msk.sin_addr.s_addr == -1) 136 usage(); 137 if (cp2 = index(cp, ',')) 138 *cp2++ = '\0'; 139 mtch.sin_addr.s_addr = inet_addr(cp); 140 if (mtch.sin_addr.s_addr == -1) 141 usage(); 142 if (cp2) 143 udpcnt = atoi(cp2); 144 if (udpcnt < 1 || udpcnt > 20) 145 udpcnt = 1; 146 } else 147 usage(); 148 break; 149 default: 150 case '?': 151 usage(); 152 } 153 154 /* 155 * Default, if neither UDP nor TCP is specified, 156 * is to support UDP only; a numeric argument indicates 157 * the number of server daemons to run. 158 */ 159 if (udpflag == 0 && tcpflag == 0) { 160 if (argc > 1) 161 udpcnt = atoi(*++argv); 162 if (udpcnt < 1 || udpcnt > 20) 163 udpcnt = 1; 164 msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0; 165 udpflag++; 166 } 167 168 if (debug == 0) { 169 daemon(0, 0); 170 signal(SIGINT, SIG_IGN); 171 signal(SIGQUIT, SIG_IGN); 172 signal(SIGTERM, SIG_IGN); 173 signal(SIGHUP, SIG_IGN); 174 } 175 signal(SIGCHLD, reapchild); 176 177 if (reregister) { 178 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, 179 NFS_PORT)) { 180 fprintf(stderr, 181 "Can't register with portmap for UDP\n"); 182 exit(1); 183 } 184 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, 185 NFS_PORT)) { 186 fprintf(stderr, 187 "Can't register with portmap for TCP\n"); 188 exit(1); 189 } 190 exit(0); 191 } 192 openlog("nfsd:", LOG_PID, LOG_DAEMON); 193 #ifdef notdef 194 /* why? unregisters both protocols even if we restart only one */ 195 pmap_unset(RPCPROG_NFS, NFS_VER2); 196 #endif 197 if (udpflag) { 198 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 199 syslog(LOG_ERR, "Can't create socket"); 200 exit(1); 201 } 202 saddr.sin_family = AF_INET; 203 saddr.sin_addr.s_addr = INADDR_ANY; 204 saddr.sin_port = htons(NFS_PORT); 205 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 206 syslog(LOG_ERR, "Can't bind addr"); 207 exit(1); 208 } 209 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) { 210 syslog(LOG_ERR, "Can't register with portmap"); 211 exit(1); 212 } 213 214 /* 215 * Send the nfs datagram servers 216 * right down into the kernel 217 */ 218 for (i = 0; i < udpcnt; i++) 219 if (fork() == 0) { 220 setproctitle("nfsd-udp", 221 (struct sockaddr_in *)NULL); 222 ret = nfssvc(sock, &msk, sizeof(msk), 223 &mtch, sizeof(mtch)); 224 if (ret < 0) 225 syslog(LOG_ERR, "nfssvc() failed %m"); 226 exit(1); 227 } 228 close(sock); 229 } 230 231 /* 232 * Now set up the master STREAM server waiting for tcp connections. 233 */ 234 if (tcpflag) { 235 int on = 1; 236 237 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 238 syslog(LOG_ERR, "Can't create socket"); 239 exit(1); 240 } 241 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 242 (char *) &on, sizeof(on)) < 0) 243 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); 244 saddr.sin_family = AF_INET; 245 saddr.sin_addr.s_addr = INADDR_ANY; 246 saddr.sin_port = htons(NFS_PORT); 247 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 248 syslog(LOG_ERR, "Can't bind addr"); 249 exit(1); 250 } 251 if (listen(sock, 5) < 0) { 252 syslog(LOG_ERR, "Listen failed"); 253 exit(1); 254 } 255 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { 256 syslog(LOG_ERR, "Can't register with portmap"); 257 exit(1); 258 } 259 setproctitle("nfsd-listen", (struct sockaddr_in *)NULL); 260 /* 261 * Loop forever accepting connections and sending the children 262 * into the kernel to service the mounts. 263 */ 264 for (;;) { 265 len = sizeof(peername); 266 if ((msgsock = accept(sock, 267 (struct sockaddr *)&peername, &len)) < 0) { 268 syslog(LOG_ERR, "Accept failed: %m"); 269 exit(1); 270 } 271 if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) != 272 mtch.sin_addr.s_addr) { 273 hp = hphead.ha_next; 274 while (hp) { 275 if (peername.sin_addr.s_addr == 276 hp->ha_sad) 277 break; 278 hp = hp->ha_next; 279 } 280 if (hp == NULL) { 281 shutdown(msgsock, 2); 282 close(msgsock); 283 continue; 284 } 285 } 286 if (fork() == 0) { 287 close(sock); 288 setproctitle("nfsd-tcp", &peername); 289 if (setsockopt(msgsock, SOL_SOCKET, 290 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) 291 syslog(LOG_ERR, 292 "setsockopt SO_KEEPALIVE: %m"); 293 ret = nfssvc(msgsock, &msk, sizeof(msk), 294 &mtch, sizeof(mtch)); 295 shutdown(msgsock, 2); 296 if (ret < 0) 297 syslog(LOG_NOTICE, 298 "Nfssvc STREAM Failed"); 299 exit(1); 300 } 301 close(msgsock); 302 } 303 } 304 } 305 306 usage() 307 { 308 fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n"); 309 exit(1); 310 } 311 312 void 313 reapchild() 314 { 315 316 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL)) 317 ; 318 } 319 320 setproctitle(a, sin) 321 char *a; 322 struct sockaddr_in *sin; 323 { 324 register char *cp; 325 char buf[80]; 326 327 cp = Argv[0]; 328 if (sin) 329 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr)); 330 else 331 (void) sprintf(buf, "%s", a); 332 (void) strncpy(cp, buf, LastArg - cp); 333 cp += strlen(cp); 334 while (cp < LastArg) 335 *cp++ = ' '; 336 } 337