rebootmgr.c (6254B)
1 // $Id$ 2 3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // based on rebootmgr.cc by Jacques Gelinas 5 // 6 // This program is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 2, or (at your option) 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program; if not, write to the Free Software 18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 20 /* 21 The reboot manager allow a virtual server administrator to request 22 a complete restart of his vserver. This means that all services 23 are terminated, all remaining processes are killed and then 24 all services are started. 25 26 This is done by issuing 27 28 /usr/sbin/vserver vserver restart 29 30 31 The rebootmgr installs a unix domain socket in each vservers 32 and listen for the reboot messages. All other message are discarded. 33 34 The unix domain socket is placed in /vservers/N/dev/reboot and is 35 turned immutable. 36 37 The vreboot utility is used to send the signal from the vserver 38 environment. 39 */ 40 #ifdef HAVE_CONFIG_H 41 # include <config.h> 42 #endif 43 #include "pathconfig.h" 44 45 #include <stdio.h> 46 #include <unistd.h> 47 #include <stdlib.h> 48 #include <sys/types.h> 49 #include <limits.h> 50 #include <errno.h> 51 #include <syslog.h> 52 #include <sys/stat.h> 53 #include <sys/time.h> 54 #include <sys/socket.h> 55 #include <sys/un.h> 56 #include <alloca.h> 57 #include <string.h> 58 59 static void usage() 60 { 61 fprintf (stderr,"rebootmgr version %s\n",VERSION); 62 fprintf (stderr,"\n"); 63 fprintf (stderr,"rebootmgr [--pidfile file ] vserver-name [ vserver-name ...]\n"); 64 } 65 66 static int rebootmgr_opensocket (const char *vname) 67 { 68 int ret = -1; 69 char sockn[PATH_MAX]; 70 int fd = socket (AF_UNIX,SOCK_STREAM,0); 71 sprintf (sockn, DEFAULT_VSERVERDIR "/%s/dev/reboot",vname); 72 unlink (sockn); 73 if (fd == -1){ 74 fprintf (stderr,"Can't create a unix domain socket (%s)\n" 75 ,strerror(errno)); 76 }else{ 77 struct sockaddr_un un; 78 un.sun_family = AF_UNIX; 79 strcpy (un.sun_path,sockn); 80 if (bind(fd,(struct sockaddr*)&un,sizeof(un))==-1){ 81 fprintf (stderr,"Can't bind to file %s (%s)\n",sockn 82 ,strerror(errno)); 83 }else{ 84 int code; 85 chmod (sockn,0600); 86 code = listen (fd,10); 87 if (code == -1){ 88 fprintf (stderr,"Can't listen to file %s (%s)\n",sockn 89 ,strerror(errno)); 90 }else{ 91 ret = fd; 92 } 93 } 94 } 95 return ret; 96 } 97 98 static int rebootmgr_process (int fd, const char *vname) 99 { 100 int ret = -1; 101 char buf[100]; 102 int len = read (fd,buf,sizeof(buf)-1); 103 // fprintf (stderr,"process %d %s len %d\n",fd,vname,len); 104 if (len > 0){ 105 buf[len] = '\0'; 106 if (strcmp(buf,"reboot\n")==0){ 107 char cmd[1000]; 108 syslog (LOG_NOTICE,"reboot vserver %s\n",vname); 109 snprintf (cmd,sizeof(cmd)-1, SBINDIR "/vserver %s restart >>/var/log/boot.log 2>&1", vname); 110 system (cmd); 111 ret = 0; 112 }else if (strcmp(buf,"halt\n")==0){ 113 char cmd[1000]; 114 syslog (LOG_NOTICE,"halt vserver %s\n",vname); 115 snprintf (cmd,sizeof(cmd)-1, SBINDIR "/vserver %s stop >>/var/log/boot.log 2>&1", vname); 116 system (cmd); 117 ret = 0; 118 }else{ 119 syslog (LOG_ERR,"Invalid request from vserver %s",vname); 120 } 121 } 122 return ret; 123 } 124 125 126 int main (int argc, char *argv[]) 127 { 128 int ret = -1; 129 if (argc < 2){ 130 usage(); 131 }else{ 132 int error = 0; 133 int start = 1; 134 int i; 135 int *sockets = alloca(argc * sizeof(int)); 136 137 openlog ("rebootmgr",LOG_PID,LOG_DAEMON); 138 for (i=0; i<argc; i++){ 139 const char *arg = argv[i]; 140 if (strcmp(arg,"--pidfile")==0){ 141 const char *pidfile = argv[i+1]; 142 FILE *fout = fopen (pidfile,"w"); 143 if (fout == NULL){ 144 fprintf (stderr,"Can't open pidfile %s (%s)\n" 145 ,pidfile,strerror(errno)); 146 147 __extension__ 148 syslog (LOG_ERR,"Can't open pidfile %s (%m)" 149 ,pidfile); 150 }else{ 151 fprintf (fout,"%d\n",getpid()); 152 fclose (fout); 153 } 154 start = i+2; 155 i++; 156 }else if (strcmp(arg,"--")==0){ 157 start = i+1; 158 break; 159 }else if (arg[0] == '-'){ 160 fprintf (stderr,"Invalid argument %s\n",arg); 161 syslog (LOG_ERR,"Invalid argument %s",arg); 162 } 163 } 164 for (i=start; i<argc; i++){ 165 int fd = rebootmgr_opensocket (argv[i]); 166 if (fd == -1){ 167 error = 1; 168 }else{ 169 sockets[i] = fd; 170 } 171 } 172 if (!error){ 173 int maxhandles = argc*2; 174 struct { 175 int handle; 176 const char *vname; 177 } handles[maxhandles]; 178 int nbhandles=0; 179 while (1){ 180 int maxfd = 0; 181 int i; 182 int ok; 183 184 fd_set fdin; 185 FD_ZERO (&fdin); 186 for (i=start; i<argc; i++){ 187 int fd = sockets[i]; 188 if (fd > maxfd) maxfd = fd; 189 FD_SET (fd,&fdin); 190 } 191 for (i=0; i<nbhandles; i++){ 192 int fd = handles[i].handle; 193 if (fd > maxfd) maxfd = fd; 194 FD_SET (fd,&fdin); 195 } 196 ok = select (maxfd+1,&fdin,NULL,NULL,NULL); 197 if (ok <= 0){ 198 break; 199 }else{ 200 int i; 201 int dst = 0; 202 203 for (i=start; i<argc; i++){ 204 int fd = sockets[i]; 205 if (FD_ISSET(fd,&fdin)){ 206 struct sockaddr_un unc; 207 socklen_t len = sizeof(unc); 208 unc.sun_family = AF_UNIX; 209 fd = accept (fd,(struct sockaddr*)&unc,&len); 210 if (fd != -1){ 211 if (nbhandles == maxhandles){ 212 int j; 213 // Overloaded, we close every handle 214 syslog (LOG_ERR,"%d sockets opened: Overloaded\n",nbhandles); 215 for (j=0; j<nbhandles; j++){ 216 close (handles[j].handle); 217 } 218 nbhandles = 0; 219 } 220 handles[nbhandles].handle = fd; 221 handles[nbhandles].vname = argv[i]; 222 nbhandles++; 223 // fprintf (stderr,"accept %d\n",nbhandles); 224 } 225 } 226 } 227 for (i=0; i<nbhandles; i++){ 228 int fd = handles[i].handle; 229 if (FD_ISSET(fd,&fdin)){ 230 if (rebootmgr_process (fd,handles[i].vname)==-1){ 231 close (fd); 232 }else{ 233 handles[dst++] = handles[i]; 234 } 235 }else{ 236 handles[dst++] = handles[i]; 237 } 238 } 239 nbhandles = dst; 240 } 241 } 242 } 243 } 244 return ret; 245 } 246 247