Subversion Repositories Mokou

Rev

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