1/* $NetBSD: cleansrv.c,v 1.3 2008/04/28 20:23:04 martin 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 54int control_socket = -1; 55extern int nfss; 56extern struct clfs **fsp; 57 58struct lfs_cleanerd_cmd { 59 int cmd; 60 int len; 61 char data[PATH_MAX]; 62}; 63 64void 65check_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 112static int 113send_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 143static void 144sig_donothing(int sig) 145{ 146 /* Do nothing */ 147 dlog("caught sigio"); 148} 149 150static void 151cleanup_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 160void 161try_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