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