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