Subversion Repositories Mokou

Rev

Rev 8 | Rev 12 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 nishi 1
/* $Id: service.c 10 2024-09-07 09:55:12Z nishi $ */
2
 
3
#include "mk_service.h"
4
 
5 nishi 5
#include <fcntl.h>
3 nishi 6
#include <stdio.h>
2 nishi 7
#include <dirent.h>
8
#include <stdlib.h>
3 nishi 9
#include <string.h>
10
#include <sys/stat.h>
5 nishi 11
#include <signal.h>
12
#include <unistd.h>
13
#include <sys/wait.h>
2 nishi 14
 
15
#include "mk_log.h"
16
#include "mk_util.h"
17
 
18
struct mk_service** services = NULL;
19
 
6 nishi 20
#ifdef __linux__
21
const char* sys_signame[] = {
8 nishi 22
	"",
6 nishi 23
	"HUP",
24
	"INT",
25
	"QUIT",
26
	"ILL",
27
	"TRAP",
28
	"ABRT",
29
	"BUS",
30
	"FPE",
31
	"KILL",
32
	"USR1",
33
	"SEGV",
34
	"USR2",
35
	"PIPE",
36
	"ALRM",
37
	"TERM",
38
	"STKFLT",
39
	"CHLD",
40
	"CONT",
41
	"STOP",
42
	"TSTP",
43
	"TTIN",
44
	"TTOU",
45
	"URG",
46
	"XCPU",
47
	"XFSZ",
48
	"VTALRM",
49
	"PROF",
50
	"WINCH",
51
	"POLL",
52
	"PWR",
53
	"SYS",
54
	"RTMIN"
55
};
56
#endif
57
 
2 nishi 58
void mk_service_scan(void){
59
	if(services != NULL){
60
		int i;
61
		for(i = 0; services[i] != NULL; i++){
5 nishi 62
			if(services[i]->name != NULL) free(services[i]->name);
63
			if(services[i]->stop != NULL) free(services[i]->stop);
4 nishi 64
			if(services[i]->description != NULL) free(services[i]->description);
65
			if(services[i]->exec != NULL) free(services[i]->exec);
66
			if(services[i]->pidfile != NULL) free(services[i]->pidfile);
2 nishi 67
			free(services[i]);
68
		}
69
		free(services);
3 nishi 70
		mk_log("Cleaning up the list");
2 nishi 71
	}
3 nishi 72
	services = malloc(sizeof(*services));
73
	services[0] = NULL;
2 nishi 74
 
75
	mk_log("Scanning the service directory.");
76
 
77
	DIR* dir = opendir(PREFIX "/etc/mokou");
78
	if(dir != NULL){
79
		struct dirent* d;
80
		while((d = readdir(dir)) != NULL){
81
			if(mk_endswith(d->d_name, ".conf")){
82
				char* path = mk_strcat(PREFIX "/etc/mokou/", d->d_name);
83
				char* str = mk_strcat("Reading ", path);
84
				mk_log(str);
85
				free(str);
3 nishi 86
 
87
				FILE* f = fopen(path, "r");
88
				if(f != NULL){
89
					struct stat s;
90
					stat(path, &s);
91
					char* buffer = malloc(s.st_size + 1);
92
					buffer[s.st_size] = 0;
93
					fread(buffer, s.st_size, 1, f);
94
					int i;
95
					int incr = 0;
96
 
97
					char* desc = NULL;
98
					char* exec = NULL;
5 nishi 99
					char* stop = NULL;
3 nishi 100
					char* pidfile = NULL;
101
 
102
					for(i = 0;; i++){
103
						if(buffer[i] == '\n' || buffer[i] == 0){
104
							char oldc = buffer[i];
105
							buffer[i] = 0;
106
 
107
							char* line = buffer + incr;
108
 
109
							if(strlen(line) > 0 && line[0] != '#'){
110
								int j;
111
 
112
								for(j = 0; line[j] != 0; j++){
113
									if(line[j] == '='){
114
										line[j] = 0;
115
 
116
										char* key = line;
117
										char* value = line + j + 1;
118
										if(strcmp(key, "description") == 0){
119
											if(desc != NULL) free(desc);
120
											desc = mk_strdup(value);
121
										}else if(strcmp(key, "exec") == 0){
122
											if(exec != NULL) free(exec);
123
											exec = mk_strdup(value);
124
										}else if(strcmp(key, "pidfile") == 0){
125
											if(pidfile != NULL) free(pidfile);
126
											pidfile = mk_strdup(value);
5 nishi 127
										}else if(strcmp(key, "stop") == 0){
128
											if(stop != NULL) free(stop);
129
											stop = mk_strdup(value);
3 nishi 130
										}
131
 
132
										break;
133
									}
134
								}
135
							}
136
 
137
							incr = i + 1;
138
							if(oldc == 0) break;
139
						}
140
					}
141
					fclose(f);
142
 
143
					bool bad = false;
144
					if(exec == NULL){
145
						char* log = mk_strcat(desc == NULL ? path : desc, ": Missing exec");
146
						mk_log(log);
147
						free(log);
148
						bad = true;
149
					}
150
					if(pidfile == NULL){
151
						char* log = mk_strcat(desc == NULL ? path : desc, ": Missing pidfile");
152
						mk_log(log);
153
						free(log);
154
						bad = true;
155
					}
156
 
157
					if(!bad){
158
						char* log = mk_strcat3("Adding ", desc == NULL ? path : desc, " to the list");
159
						mk_log(log);
160
						free(log);
4 nishi 161
 
5 nishi 162
						int i;
4 nishi 163
						struct mk_service* serv = malloc(sizeof(*serv));
5 nishi 164
						serv->name = mk_strdup(d->d_name);
165
 
166
						for(i = strlen(d->d_name) - 1; i >= 0; i--){
167
							if(serv->name[i] == '.'){
168
								serv->name[i] = 0;
169
								break;
170
							}
171
						}
172
 
4 nishi 173
						serv->description = desc != NULL ? mk_strdup(desc) : NULL;
5 nishi 174
						serv->stop = stop != NULL ? mk_strdup(stop) : NULL;
4 nishi 175
						serv->exec = mk_strdup(exec);
176
						serv->pidfile = mk_strdup(pidfile);
5 nishi 177
						serv->stopped = false;
178
 
179
						struct mk_service** oldsrvs = services;
180
						for(i = 0; oldsrvs[i] != NULL; i++);
181
						services = malloc(sizeof(*services) * (i + 2));
182
						for(i = 0; oldsrvs[i] != NULL; i++){
183
							services[i] = oldsrvs[i];
184
						}
185
						services[i] = serv;
186
						services[i + 1] = NULL;
187
						free(oldsrvs);
3 nishi 188
					}
189
 
190
					if(desc != NULL) free(desc);
191
					if(exec != NULL) free(exec);
192
					if(pidfile != NULL) free(pidfile);
193
				}
194
 
2 nishi 195
				free(path);
196
			}
197
		}
198
		closedir(dir);
199
	}else{
200
		mk_log("Cannot open the directory.");
201
	}
202
}
5 nishi 203
 
8 nishi 204
const char* mk_errors[] = {
5 nishi 205
	"Success",
206
	"No such service",
207
	"Service is alive",
208
	"Failed to start",
209
	"Service is dead",
210
	"Bad signal",
211
	"Could not stop the service"
212
};
213
 
214
int mk_stop_service(const char* name){
215
	int i;
216
	for(i = 0; services[i] != NULL; i++){
217
		if(strcmp(services[i]->name, name) == 0){
218
			struct mk_service* srv = services[i];
219
			char* log = mk_strcat("Stopping ", name);
220
			mk_log(log);
221
			free(log);
222
 
223
			bool alive = false;
224
 
225
			FILE* f = fopen(srv->pidfile, "r");
226
			unsigned long long pid;
227
			if(f != NULL){
228
				fscanf(f, "%llu", &pid);
229
				fclose(f);
230
				alive = kill(pid, 0) == 0;
231
			}
232
 
233
			if(!alive){
234
				mk_log("Process seems to be dead, not stopping");
235
				return 4;
236
			}
237
 
238
			if(srv->stop == NULL || srv->stop[0] == '#'){
239
				int sig = -1;
240
				if(srv->stop == NULL){
241
					sig = SIGINT;
242
				}
243
				if(sig == -1){
244
					int i;
245
					for(i = 1; i < NSIG; i++){
246
						if(strcmp(sys_signame[i], srv->stop + 1) == 0){
247
							sig = i;
248
							break;
249
						}
250
					}
251
				}
252
				if(sig == -1){
253
					mk_log("Bad signal");
254
					return 5;
255
				}else{
256
					log = mk_strcat("Sending SIG", sys_signame[sig]);
257
					mk_log(log);
258
					free(log);
259
					bool dead = false;
260
					kill(pid, sig);
261
					for(i = 0; i < 3; i++){
262
						if(kill(pid, 0) == -1){
263
							mk_log("Process died");
264
							dead = true;
265
							break;
266
						}else{
267
							mk_log("Process is still alive");
268
						}
269
						if(i != 2) sleep(1);
270
					}
271
					if(!dead){
272
						mk_log("Could not kill the process");
273
						return 6;
274
					}
275
				}
276
			}else{
277
				char** pargv = malloc(sizeof(*pargv));
278
				pargv[0] = NULL;
279
 
280
				int i;
281
				int incr = 0;
282
				for(i = 0;; i++){
283
					if(srv->stop[i] == 0 || srv->stop[i] == ' '){
284
						char* str = malloc(i - incr + 1);
285
						memcpy(str, srv->stop + incr, i - incr);
286
						str[i - incr] = 0;
287
 
288
						char** oldargv = pargv;
289
						int j;
290
						for(j = 0; oldargv[j] != NULL; j++);
291
						pargv = malloc(sizeof(*pargv) * (j + 2));
292
						for(j = 0; oldargv[j] != NULL; j++) pargv[j] = oldargv[j];
293
						pargv[j] = str;
294
						pargv[j + 1]  = NULL;
295
						free(oldargv);
296
 
297
						incr = i + 1;
298
						if(srv->exec[i] == 0) break;
299
					}
300
				}
301
			}
302
 
303
			srv->stopped = true;
304
			return 0;
305
		}
306
	}
307
	return 1;
308
}
309
 
310
int mk_start_service(const char* name){
311
	int i;
312
	for(i = 0; services[i] != NULL; i++){
313
		if(strcmp(services[i]->name, name) == 0){
314
			struct mk_service* srv = services[i];
315
			char* log = mk_strcat("Starting ", name);
316
			mk_log(log);
317
			free(log);
318
 
319
			bool alive = false;
320
 
321
			FILE* f = fopen(srv->pidfile, "r");
322
			if(f != NULL){
323
				unsigned long long pid;
324
				fscanf(f, "%llu", &pid);
325
				fclose(f);
326
				alive = kill(pid, 0) == 0;
327
			}
328
			if(alive){
329
				mk_log("Process seems to be alive, not starting");
330
				return 2;
331
			}
332
 
333
			char** pargv = malloc(sizeof(*pargv));
334
			pargv[0] = NULL;
335
 
336
			int i;
337
			int incr = 0;
338
			for(i = 0;; i++){
339
				if(srv->exec[i] == 0 || srv->exec[i] == ' '){
340
					char* str = malloc(i - incr + 1);
341
					memcpy(str, srv->exec + incr, i - incr);
342
					str[i - incr] = 0;
343
 
344
					char** oldargv = pargv;
345
					int j;
346
					for(j = 0; oldargv[j] != NULL; j++);
347
					pargv = malloc(sizeof(*pargv) * (j + 2));
348
					for(j = 0; oldargv[j] != NULL; j++) pargv[j] = oldargv[j];
349
					pargv[j] = str;
350
					pargv[j + 1]  = NULL;
351
					free(oldargv);
352
 
353
					incr = i + 1;
354
					if(srv->exec[i] == 0) break;
355
				}
356
			}
357
 
358
			bool fail = false;
359
 
360
			pid_t pid = fork();
361
			if(pid == 0){
362
				int n = open("/dev/null", O_RDWR);
363
				dup2(n, 1);
364
				dup2(n, 2);
365
				execvp(pargv[0], pargv);
366
				_exit(-1);
367
			}else{
368
				int status;
369
				waitpid(pid, &status, 0);
370
				if(WEXITSTATUS(status) != 0) fail = true;
371
			}
372
			for(i = 0; pargv[i] != NULL; i++) free(pargv[i]);
373
			free(pargv);
374
			if(fail){
375
				log = mk_strcat("Failed to start ", name);
376
				mk_log(log);
377
				free(log);
378
				srv->stopped = false;
379
				return 3;
380
			}else{
381
				log = mk_strcat("Started ", name);
382
				mk_log(log);
383
				free(log);
384
				srv->stopped = false;
385
			}
386
 
387
			return 0;
388
		}
389
	}
390
	return 1;
391
}
392
 
393
void mk_start_services(void){
394
	int i;
395
	for(i = 0; services[i] != NULL; i++){
396
		mk_start_service(services[i]->name);
397
	}
398
}
10 nishi 399
 
400
void mk_resurrect_services(void){
401
	int i;
402
	bool re = false;
403
	for(i = 0; services[i] != NULL; i++){
404
		if(!services[i]->stopped){
405
			bool alive = false;
406
 
407
			FILE* f = fopen(services[i]->pidfile, "r");
408
			if(f != NULL){
409
				unsigned long long pid;
410
				fscanf(f, "%llu", &pid);
411
				fclose(f);
412
				alive = kill(pid, 0) == 0;
413
			}
414
			if(!alive){
415
				if(!re){
416
					mk_log("Resurrection");
417
					re = true;
418
				}
419
				mk_start_service(services[i]->name);
420
			}
421
		}
422
	}
423
}