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