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