This commit was generated by cvs2svn to compensate for changes in r120,
[util-vserver.git] / src / rebootmgr.c
1 // $Id: rebootmgr.c,v 1.1.2.1.2.3 2003/10/30 15:16:30 ensc Exp $
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 "compat.h"
44
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <sys/types.h>
49 #include <errno.h>
50 #include <syslog.h>
51 #include <sys/stat.h>
52 #include <sys/time.h>
53 #include <sys/socket.h>
54 #include <sys/un.h>
55 #include <alloca.h>
56
57 static void usage()
58 {
59         fprintf (stderr,"rebootmgr version %s\n",VERSION);
60         fprintf (stderr,"\n");
61         fprintf (stderr,"rebootmgr [--pidfile file ] vserver-name [ vserver-name ...]\n");
62 }
63
64 static int rebootmgr_opensocket (const char *vname)
65 {
66         int ret = -1;
67         char sockn[PATH_MAX];
68         int fd =  socket (AF_UNIX,SOCK_STREAM,0);
69         sprintf (sockn,"%s/%s/dev/reboot",VROOTDIR, vname);
70         unlink (sockn);
71         if (fd == -1){
72                 fprintf (stderr,"Can't create a unix domain socket (%s)\n"
73                                 ,strerror(errno));
74         }else{
75                 struct sockaddr_un un;
76                 un.sun_family = AF_UNIX;
77                 strcpy (un.sun_path,sockn);
78                 if (bind(fd,(struct sockaddr*)&un,sizeof(un))==-1){
79                         fprintf (stderr,"Can't bind to file %s (%s)\n",sockn
80                                 ,strerror(errno));
81                 }else{
82                         int code;
83                         chmod (sockn,0600);
84                         code = listen (fd,10);
85                         if (code == -1){
86                                 fprintf (stderr,"Can't listen to file %s (%s)\n",sockn
87                                         ,strerror(errno));
88                         }else{
89                                 ret = fd;
90                         }       
91                 }
92         }
93         return ret;
94 }
95
96 static int rebootmgr_process (int fd, const char *vname)
97 {
98         int ret = -1;
99         char buf[100];
100         int len = read (fd,buf,sizeof(buf)-1);
101         // fprintf (stderr,"process %d %s len %d\n",fd,vname,len);
102         if (len > 0){
103                 buf[len] = '\0';
104                 if (strcmp(buf,"reboot\n")==0){
105                         char cmd[1000];
106                         syslog (LOG_NOTICE,"reboot vserver %s\n",vname);
107                         snprintf (cmd,sizeof(cmd)-1,"%s/vserver %s restart >>/var/log/boot.log 2>&1",SBINDIR, vname);
108                         system (cmd);
109                         ret = 0;
110                 }else if (strcmp(buf,"halt\n")==0){
111                         char cmd[1000];
112                         syslog (LOG_NOTICE,"halt vserver %s\n",vname);
113                         snprintf (cmd,sizeof(cmd)-1,"%s/vserver %s stop >>/var/log/boot.log 2>&1",SBINDIR, vname);
114                         system (cmd);
115                         ret = 0;
116                 }else{
117                         syslog (LOG_ERR,"Invalid request from vserver %s",vname);
118                 }
119         }
120         return ret;
121 }
122
123
124 int main (int argc, char *argv[])
125 {
126         int ret = -1;
127         if (argc < 2){
128                 usage();
129         }else{
130                 int error = 0;
131                 int start = 1;
132                 int i;
133                 int *sockets = alloca(argc * sizeof(int));
134
135                 openlog ("rebootmgr",LOG_PID,LOG_DAEMON);
136                 for (i=0; i<argc; i++){
137                         const char *arg = argv[i];
138                         if (strcmp(arg,"--pidfile")==0){
139                                 const char *pidfile = argv[i+1];
140                                 FILE *fout = fopen (pidfile,"w");
141                                 if (fout == NULL){
142                                         fprintf (stderr,"Can't open pidfile %s (%s)\n"
143                                                 ,pidfile,strerror(errno));
144
145                                         __extension__
146                                         syslog (LOG_ERR,"Can't open pidfile %s (%m)"
147                                                 ,pidfile);
148                                 }else{
149                                         fprintf (fout,"%d\n",getpid());
150                                         fclose (fout);
151                                 }
152                                 start = i+2;
153                                 i++;
154                         }else if (strcmp(arg,"--")==0){
155                                 start = i+1;
156                                 break;
157                         }else if (arg[0] == '-'){
158                                 fprintf (stderr,"Invalid argument %s\n",arg);
159                                 syslog (LOG_ERR,"Invalid argument %s",arg);
160                         }
161                 }
162                 for (i=start; i<argc; i++){
163                         int fd = rebootmgr_opensocket (argv[i]);
164                         if (fd == -1){
165                                 error = 1;
166                         }else{
167                                 sockets[i] = fd;
168                         }
169                 }
170                 if (!error){
171                         int maxhandles = argc*2;
172                         struct {
173                                 int handle;
174                                 const char *vname;
175                         } handles[maxhandles];
176                         int nbhandles=0;
177                         while (1){
178                                 int maxfd = 0;
179                                 int i;
180                                 int ok;
181                                 
182                                 fd_set fdin;
183                                 FD_ZERO (&fdin);
184                                 for (i=start; i<argc; i++){
185                                         int fd = sockets[i];
186                                         if (fd > maxfd) maxfd = fd;
187                                         FD_SET (fd,&fdin);
188                                 }
189                                 for (i=0; i<nbhandles; i++){
190                                         int fd = handles[i].handle;
191                                         if (fd > maxfd) maxfd = fd;
192                                         FD_SET (fd,&fdin);
193                                 }
194                                 ok = select (maxfd+1,&fdin,NULL,NULL,NULL);
195                                 if (ok <= 0){
196                                         break;
197                                 }else{
198                                         int i;
199                                         int dst = 0;
200
201                                         for (i=start; i<argc; i++){
202                                                 int fd = sockets[i];
203                                                 if (FD_ISSET(fd,&fdin)){
204                                                         struct sockaddr_un unc;
205                                                         socklen_t len = sizeof(unc);
206                                                         unc.sun_family = AF_UNIX;
207                                                         fd = accept (fd,(struct sockaddr*)&unc,&len);
208                                                         if (fd != -1){
209                                                                 if (nbhandles == maxhandles){
210                                                                         int j;
211                                                                         // Overloaded, we close every handle
212                                                                         syslog (LOG_ERR,"%d sockets opened: Overloaded\n",nbhandles);
213                                                                         for (j=0; j<nbhandles; j++){
214                                                                                 close (handles[j].handle);
215                                                                         }
216                                                                         nbhandles = 0;
217                                                                 }
218                                                                 handles[nbhandles].handle = fd;
219                                                                 handles[nbhandles].vname = argv[i];
220                                                                 nbhandles++;
221                                                                 // fprintf (stderr,"accept %d\n",nbhandles);
222                                                         }
223                                                 }
224                                         }
225                                         for (i=0; i<nbhandles; i++){
226                                                 int fd = handles[i].handle;
227                                                 if (FD_ISSET(fd,&fdin)){
228                                                         if (rebootmgr_process (fd,handles[i].vname)==-1){
229                                                                 close (fd);
230                                                         }else{
231                                                                 handles[dst++] = handles[i];
232                                                         }
233                                                 }else{
234                                                         handles[dst++] = handles[i];
235                                                 }
236                                         }
237                                         nbhandles = dst;
238                                 }
239                         }
240                 }
241         }
242         return ret;
243 }
244
245