Patch from Kent Robotti to being fdisk in sync with v2.12 final.
[oweals/busybox.git] / init / msvc.c
1 /*
2  *  minit version 0.9.1 by Felix von Leitner
3  *  ported to busybox by Glenn McGrath <bug1@optushome.com.au>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <sys/fcntl.h>
21 #include <sys/file.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "busybox.h"
29
30 static int infd, outfd;
31
32 static char buf[1500];
33
34 static unsigned int fmt_ulong(char *dest, unsigned long i)
35 {
36         register unsigned long len, tmp, len2;
37
38         /* first count the number of bytes needed */
39         for (len = 1, tmp = i; tmp > 9; ++len)
40                 tmp /= 10;
41         if (dest)
42                 for (tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10)
43                         *--dest = (tmp % 10) + '0';
44         return len;
45 }
46
47 static void addservice(char *service)
48 {
49         char *service_ptr;
50
51         if (strncmp(service, "/etc/minit/", 11) == 0) {
52                 service += 11;
53         }
54
55         while ((service_ptr = last_char_is(service, '/')) != NULL) {
56                 *service_ptr = 0;
57         }
58         strncpy(buf + 1, service, 1400);
59         buf[1400] = 0;
60 }
61
62 static int addreadwrite(char *service)
63 {
64         addservice(service);
65         write(infd, buf, strlen(buf));
66         return read(outfd, buf, 1500);
67 }
68
69 /* return PID, 0 if error */
70 static pid_t __readpid(char *service)
71 {
72         int len;
73
74         buf[0] = 'p';
75         len = addreadwrite(service);
76         if (len < 0)
77                 return 0;
78         buf[len] = 0;
79         return atoi(buf);
80 }
81
82 /* return nonzero if error */
83 static int respawn(char *service, int yesno)
84 {
85         int len;
86
87         buf[0] = yesno ? 'R' : 'r';
88         len = addreadwrite(service);
89         return (len != 1 || buf[0] == '0');
90 }
91
92 /* return nonzero if error */
93 static int startservice(char *service)
94 {
95         int len;
96
97         buf[0] = 's';
98         len = addreadwrite(service);
99         return (len != 1 || buf[0] == '0');
100 }
101
102 extern int msvc_main(int argc, char **argv)
103 {
104         if (argc < 2) {
105                 bb_show_usage();
106         }
107         infd = bb_xopen("/etc/minit/in", O_WRONLY);
108         outfd = bb_xopen("/etc/minit/out", O_RDONLY);
109
110         while (lockf(infd, F_LOCK, 1)) {
111                 bb_perror_msg("could not aquire lock!\n");
112                 sleep(1);
113         }
114
115         if (argc == 2) {
116                 pid_t pid = __readpid(argv[1]);
117
118                 if (buf[0] != '0') {
119                         int len;
120                         int up_time;
121
122                         printf("%s: ", argv[1]);
123                         if (pid == 0)
124                                 printf("down ");
125                         else if (pid == 1)
126                                 printf("finished ");
127                         else {
128                                 printf("up (pid %d) ", pid);
129                         }
130
131                         buf[0] = 'u';
132                         len = addreadwrite(argv[1]);
133                         if (len < 0) {
134                                 up_time = 0;
135                         } else {
136                                 buf[len] = 0;
137                                 up_time = atoi(buf);
138                         }
139                         printf("%d seconds\n", up_time);
140
141                         if (pid == 0)
142                                 return 2;
143                         else if (pid == 1)
144                                 return 3;
145                         else
146                                 return 0;
147                 } else {
148                         bb_error_msg_and_die("no such service");
149                 }
150         } else {
151                 int i;
152                 int ret = 0;
153                 int sig = 0;
154                 pid_t pid;
155
156                 if (argv[1][0] == '-') {
157                         switch (argv[1][1]) {
158                         case 'g':
159                                 for (i = 2; i < argc; ++i) {
160                                         pid = __readpid(argv[i]);
161                                         if (pid < 2) {
162                                                 if (pid == 1) {
163                                                         bb_error_msg("%s, service termination", argv[i]);
164                                                 } else {
165                                                         bb_error_msg("%s, no such service", argv[i]);
166                                                 }
167                                                 ret = 1;
168                                         }
169                                         printf("%d\n", pid);
170                                 }
171                                 break;
172                         case 'p':
173                                 sig = SIGSTOP;
174                                 goto dokill;
175                                 break;
176                         case 'c':
177                                 sig = SIGCONT;
178                                 goto dokill;
179                                 break;
180                         case 'h':
181                                 sig = SIGHUP;
182                                 goto dokill;
183                                 break;
184                         case 'a':
185                                 sig = SIGALRM;
186                                 goto dokill;
187                                 break;
188                         case 'i':
189                                 sig = SIGINT;
190                                 goto dokill;
191                                 break;
192                         case 't':
193                                 sig = SIGTERM;
194                                 goto dokill;
195                                 break;
196                         case 'k':
197                                 sig = SIGKILL;
198                                 goto dokill;
199                                 break;
200                         case 'o':
201                                 for (i = 2; i < argc; ++i)
202                                         if (startservice(argv[i]) || respawn(argv[i], 0)) {
203                                                 bb_error_msg("Couldnt not start %s\n", argv[i]);
204                                                 ret = 1;
205                                         }
206                                 break;
207                         case 'd':
208                                 for (i = 2; i < argc; ++i) {
209                                         pid = __readpid(argv[i]);
210                                         if (pid == 0) {
211                                                 bb_error_msg("%s, no such service\n", argv[i]);
212                                                 ret = 1;
213                                         } else if (pid == 1)
214                                                 continue;
215                                         if (respawn(argv[i], 0) || kill(pid, SIGTERM)
216                                                 || kill(pid, SIGCONT));
217                                 }
218                                 break;
219                         case 'u':
220                                 for (i = 2; i < argc; ++i) {
221                                         if (startservice(argv[i]) || respawn(argv[i], 1)) {
222                                                 bb_error_msg("Couldnt not start %s\n", argv[i]);
223                                                 ret = 1;
224                                         }
225                                         break;
226                                 }
227                         case 'C':
228                                 for (i = 2; i < argc; ++i) {
229                                         int len;
230
231                                         buf[0] = 'C';
232                                         len = addreadwrite(argv[i]);
233                                         if (len != 1 || buf[0] == '0') {
234                                                 bb_error_msg("%s has terminated or was killed\n",
235                                                                          argv[i]);
236                                                 ret = 1;
237                                         }
238                                 }
239                                 break;
240                         case 'P':
241                                 pid = atoi(argv[1] + 2);
242                                 if (pid > 1) {
243                                         char *tmp;
244                                         int len;
245
246                                         buf[0] = 'P';
247                                         addservice(argv[2]);
248                                         tmp = buf + strlen(buf) + 1;
249                                         tmp[fmt_ulong(tmp, pid)] = 0;
250                                         write(infd, buf, strlen(buf) + strlen(tmp) + 2);
251                                         len = read(outfd, buf, 1500);
252                                         if (len != 1 || buf[0] == '0') {
253                                                 bb_error_msg_and_die("Couldnt not set pid of service %s\n", argv[2]);
254                                         }
255                                 }
256                                 break;
257                         default:
258                                 bb_show_usage();
259                         }
260                 } else {
261                         bb_show_usage();
262                 }
263                 return ret;
264 dokill:
265                 for (i = 2; i < argc; i++) {
266                         pid = __readpid(argv[i]);
267                         if (!pid) {
268                                 bb_error_msg("%s no such service\n", argv[i]);
269                                 ret = 1;
270                         }
271                         if (kill(pid, sig)) {
272                                 bb_error_msg("%s, could not send signal %d to PID %d\n",
273                                                          argv[i], sig, pid);
274                                 ret = 1;
275                         }
276                 }
277                 return ret;
278         }
279 }
280
281 /*
282   -u   Up.  If the service is not running, start it.  If the service stops,
283        restart it.
284   -d   Down.  If the service is running, send it a TERM signal and then a CONT
285        signal.  After it stops, do not restart it.
286   -o   Once.  If the service is not running, start it.  Do not restart it if it
287        stops.
288   -r   Tell supervise that the service is normally running; this affects status
289        messages.
290   -s   Tell supervise that the service is normally stopped; this affects status
291        messages.
292   -p   Pause.  Send the service a STOP signal.
293   -c   Continue.  Send the service a CONT signal.
294   -h   Hangup.  Send the service a HUP signal.
295   -a   Alarm.  Send the service an ALRM signal.
296   -i   Interrupt.  Send the service an INT signal.
297   -t   Terminate.  Send the service a TERM signal.
298   -k   Kill.  Send the service a KILL signal.
299   -x   Exit.  supervise will quit as soon as the service is down.
300 */