1 /* $NetBSD: cleansrv.c,v 1.2 2006/05/12 19:33:02 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #ifdef USE_CLIENT_SERVER 40 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <sys/syslog.h> 45 #include <sys/param.h> 46 #include <sys/mount.h> 47 #include <sys/socket.h> 48 #include <sys/un.h> 49 #include <ufs/ufs/inode.h> 50 #include <ufs/lfs/lfs.h> 51 52 #include "bufcache.h" 53 #include "vnode.h" 54 #include "lfs.h" 55 #include "fdfs.h" 56 #include "cleaner.h" 57 58 #define LFS_CLEANERD_SOCKDIR "/tmp/.lfs_cleanerd" 59 #define LFS_CLEANERD_SOCKFILE LFS_CLEANERD_SOCKDIR "/socket" 60 61 int control_socket = -1; 62 extern int nfss; 63 extern struct clfs **fsp; 64 65 struct lfs_cleanerd_cmd { 66 int cmd; 67 int len; 68 char data[PATH_MAX]; 69 }; 70 71 void 72 check_control_socket(void) 73 { 74 int c, r; 75 struct lfs_cleanerd_cmd cmd; 76 struct clfs **nfsp; 77 78 if (control_socket < 0) 79 return; 80 81 while(1) { 82 ioctl(control_socket, FIONREAD, &c); 83 if (c <= 0) 84 return; 85 read(control_socket, (char *)&cmd, sizeof(cmd)); 86 87 switch(cmd.cmd) { 88 case 'C': /* Add filesystem for cleaning */ 89 ++nfss; 90 nfsp = (struct clfs **)realloc(fsp, 91 nfss * sizeof(*fsp)); 92 if (nfsp == NULL) { 93 --nfss; 94 break; 95 } 96 fsp = nfsp; 97 98 fsp[nfss - 1] = (struct clfs *)malloc(sizeof(**fsp)); 99 if (fsp[nfss - 1] == NULL) { 100 syslog(LOG_ERR, "%s: couldn't alloc memory: %m" 101 cmd.data); 102 --nfsp; 103 break; 104 } 105 106 if ((r = init_fs(fsp[nfss - 1], cmd.data)) < 0) { 107 syslog(LOG_ERR, "%s: couldn't init: " 108 "error code %d", cmd.data, r); 109 handle_error(fsp, nfss - 1); 110 } 111 break; 112 default: 113 syslog(LOG_NOTICE, "unknown message type %d", cmd.cmd); 114 break; 115 } 116 } 117 } 118 119 static int 120 send_fss_to_master(int argc, char **argv) 121 { 122 struct sockaddr_un sun; 123 struct lfs_cleanerd_cmd cmd; 124 int i, r, s; 125 126 strcpy(sun.sun_path, LFS_CLEANERD_SOCKFILE); 127 sun.sun_family = AF_LOCAL; 128 sun.sun_len = sizeof(sa_family_t) + 1 + strlen(sun.sun_path); 129 130 s = socket(PF_LOCAL, SOCK_DGRAM, 0); 131 if (s < 0) { 132 syslog(LOG_DEBUG, "open failed: %m"); 133 return -1; 134 } 135 136 cmd.cmd = 'C'; 137 for (i = 0; i < argc; i++) { 138 strncpy(cmd.data, argv[i], PATH_MAX); 139 cmd.len = 2 * sizeof(int) + strlen(cmd.data) + 1; 140 r = sendto(s, &cmd, sizeof(cmd), 0, (struct sockaddr *)&sun, 141 sizeof(sun)); 142 if (r < 0) { 143 syslog(LOG_DEBUG, "sendto failed: %m"); 144 return -1; 145 } 146 } 147 return 0; 148 } 149 150 static void 151 sig_donothing(int sig) 152 { 153 /* Do nothing */ 154 dlog("caught sigio"); 155 } 156 157 static void 158 cleanup_socket(void) 159 { 160 if (control_socket >= 0) { 161 close(control_socket); 162 unlink(LFS_CLEANERD_SOCKFILE); 163 rmdir(LFS_CLEANERD_SOCKDIR); 164 } 165 } 166 167 void 168 try_to_become_master(int argc, char **argv) 169 { 170 struct sockaddr_un sun; 171 int fd; 172 int pid; 173 int flags; 174 char scratch[80]; 175 176 if (mkdir(LFS_CLEANERD_SOCKDIR, 0700) < 0) { 177 if (errno != EEXIST) 178 return; 179 pid = 0; 180 fd = open("/var/run/lfs_cleanerd.pid", O_RDONLY); 181 if (fd >= 0) { 182 read(fd, scratch, 80); 183 scratch[79] = '\0'; 184 pid = atoi(scratch); 185 if (kill(pid, 0) == 0) { 186 send_fss_to_master(argc, argv); 187 exit(0); 188 } 189 close(fd); 190 } 191 192 /* 193 * Master is no longer present even though directory 194 * exists. Remove the socket and proceed. There is 195 * a race condition here which could result in more than 196 * one master daemon. That would not be a catastrophe. 197 */ 198 if (unlink(LFS_CLEANERD_SOCKFILE) != 0) 199 return; 200 } 201 202 /* 203 * Create the socket and bind it in the namespace 204 */ 205 control_socket = socket(PF_LOCAL, SOCK_DGRAM, 0); 206 strcpy(sun.sun_path, LFS_CLEANERD_SOCKFILE); 207 sun.sun_family = AF_LOCAL; 208 sun.sun_len = sizeof(sa_family_t) + 1 + strlen(sun.sun_path); 209 bind(control_socket, (struct sockaddr *)&sun, sizeof(sun)); 210 211 /* Clean up when we leave */ 212 atexit(cleanup_socket); 213 214 /* 215 * Wake us when there is i/o on this socket. We don't need 216 * to actually do anything when we get the signal, but we 217 * have to install a signal handler so LFCNSEGWAIT will be 218 * interrupted when data comes in on the socket. 219 */ 220 fcntl(control_socket, F_SETOWN, getpid()); 221 flags = fcntl(control_socket, F_GETFL, NULL); 222 flags |= O_ASYNC; 223 fcntl(control_socket, F_SETFL, flags); 224 signal(SIGIO, sig_donothing); 225 226 /* And finally record our pid */ 227 pidfile("lfs_cleanerd"); 228 } 229 #endif /* USE_CLIENT_SERVER */ 230