Subversion Repositories general

Rev

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

Rev Author Line No. Line
1140 dev 1
/******************************************************************
1159 dev 2
 * rebootd.
1140 dev 3
 *
1168 dev 4
 * A daemon which waits on specified UDP port for special string
1159 dev 5
 * (password) and reboots the computer.
1140 dev 6
 *
1164 dev 7
 * Command line: rebootd [--version] [--help] [--interface IP] [--port PORT] [--config CONFIG_FILE]
1159 dev 8
 * Defaults are port 19 and config /etc/rebootd.conf.
1140 dev 9
 *
10
 * Config file looks like:
11
 * --------------------------
1164 dev 12
 * interface=192.168.0.1
1140 dev 13
 * port=19
14
 * password="some password"
15
 * --------------------------
16
 *
17
 * Usage example (from any other host):
1168 dev 18
 * echo -n "some password" | nc -uo host_to_rebot 19
1140 dev 19
 *
20
 * Copyleft 2005 Anatoli Klassen
21
 *
22
 ******************************************************************/
23
 
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <string.h>
27
#include <stdarg.h>
1144 dev 28
#include <ctype.h>
1140 dev 29
#include <errno.h>
30
#include <signal.h>
31
#include <unistd.h>
32
#include <netdb.h>
33
#include <syslog.h>
1165 dev 34
#include <signal.h>
35
#include <fcntl.h>
1140 dev 36
#include <sys/types.h>
1144 dev 37
#include <sys/stat.h>
1140 dev 38
#include <sys/socket.h>
39
#include <sys/wait.h>
40
#include <sys/reboot.h>
41
#include <netinet/in.h>
42
#include <arpa/inet.h>
43
 
1145 dev 44
/* name version number */
1159 dev 45
#define APP_NAME          "rebootd"
1145 dev 46
#define VERSION           "1.0"
47
#define REVISION          "$Rev: 1168 $"
1144 dev 48
 
1145 dev 49
#define DEFAULT_PORT      19
1159 dev 50
#define DEFAULT_CFG_FILE  "/etc/rebootd.conf"
1145 dev 51
#define CMDSIZE           4096
52
#define BUFSIZE           4096
53
#define MAX_CONFIG_LINE   4096
54
#define PORT_MIN          1
55
#define PORT_MAX          65535
1140 dev 56
 
1145 dev 57
/* return values of functions */
58
#define RESULT_OK         0
59
#define RESULT_EXIT       1
60
#define RESULT_ERROR      2
61
#define RESULT_UNEXPECTED 3
1140 dev 62
 
1145 dev 63
/* return values for the whole program */
64
#define EXIT_OK           0
65
#define EXIT_USER_ERROR   1
66
#define EXIT_UNEXPECTED   2
67
 
68
/* command line and config file parameters */
69
#define PARAM_HELP_1      "-h"
70
#define PARAM_HELP_2      "--help"
1165 dev 71
#define PARAM_VERSION     "--version"
72
#define PARAM_INTERFACE   "--interface"
73
#define PARAM_PORT        "--port"
74
#define PARAM_CONFIG      "--config"
75
#define PARAM_PID_FILE    "--pid"
1164 dev 76
#define CONFIG_INTERFACE  "interface"
1145 dev 77
#define CONFIG_PORT       "port"
78
#define CONFIG_PASSWORD   "password"
1165 dev 79
#define CONFIG_PID_FILE   "pid"
1145 dev 80
 
1165 dev 81
/* priority of defferent sources of options */
82
#define CFG_PRIO_CMD      1
83
#define CFG_PRIO_CONFIG   2
84
#define CFG_PRIO_DEFAULT  3
85
 
1140 dev 86
struct config {
1164 dev 87
	char           config_file[FILENAME_MAX];
1165 dev 88
	char           config_file_prio;
1164 dev 89
	struct in_addr interface;
1165 dev 90
	char           interface_prio;
1164 dev 91
	ushort         port;
1165 dev 92
	char           port_prio;
1164 dev 93
	char           password[MAX_CONFIG_LINE];
1165 dev 94
	char           password_prio;
95
	char           pid_file[FILENAME_MAX];
96
	char           pid_file_prio;
1140 dev 97
};
1165 dev 98
 
99
static struct config global_cfg;
100
static int           daemonized      = 0; /* we are already a daemon */
101
volatile static int  reconfig_needed = 0; /* we have to stop socket listening and reread config */
1140 dev 102
 
1163 dev 103
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[]);
104
static int parse_config_file(struct config *cfg, const char *config_name);
1156 dev 105
static int get_revision(void);
1165 dev 106
static void check_return(int res);
1140 dev 107
 
1156 dev 108
static uint min(uint a, uint b)
1140 dev 109
{
110
	return (a < b) ? a : b;
111
}
112
 
1164 dev 113
static int establish(const struct config *cfg)
1140 dev 114
{
115
	int s;
116
	struct sockaddr_in sa;
117
 
118
	memset(&sa, 0, sizeof(struct sockaddr_in));
119
 
120
	sa.sin_family      = AF_INET;
1164 dev 121
	sa.sin_port        = htons(cfg->port);
122
	sa.sin_addr.s_addr = (cfg->interface.s_addr ? cfg->interface.s_addr : INADDR_ANY);
1140 dev 123
 
1168 dev 124
	if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1140 dev 125
		return -1;
126
 
127
	if(bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
128
		close(s);
129
		return -1;
130
	}
131
 
132
	return s;
133
}
134
 
1156 dev 135
static void listen_socket(const struct config *cfg, int soc)
1142 dev 136
{
1168 dev 137
	char                    buf[BUFSIZE];
138
	int                     br;
139
	struct sockaddr_storage ss;
140
	socklen_t               ss_size;
1142 dev 141
 
142
	for(;;) {
1168 dev 143
		ss_size = sizeof(ss);
144
		br = recvfrom(soc, buf, sizeof(buf)-1, 0, (struct sockaddr *)&ss, &ss_size);
145
 
146
		if(br == 0) {
147
			if(reconfig_needed) return;
1142 dev 148
			continue;
149
		}
1168 dev 150
		else if(br < 0) {
151
			syslog(LOG_INFO, "cannot receive: %s", strerror(errno));
152
			continue;
153
		}
1142 dev 154
 
1168 dev 155
		buf[br] = '\0';
1142 dev 156
		sleep(1);
1147 dev 157
		syslog(LOG_INFO, "got command");
1142 dev 158
 
1168 dev 159
		if(0 == strncmp(buf, cfg->password, sizeof(buf))) {
1142 dev 160
			syslog(LOG_EMERG, "REBOOT");
161
			sleep(5);
162
			if(reboot(RB_AUTOBOOT) < 0) {
1168 dev 163
				syslog(LOG_ERR, "cannot reboot, %s", strerror(errno));
1142 dev 164
			}
165
		}
166
	}
167
}
168
 
1156 dev 169
static void print_version(void)
1140 dev 170
{
1145 dev 171
	printf("%s %s.%d\n", APP_NAME, VERSION, get_revision());
172
}
173
 
1156 dev 174
static void pring_usage(int argc, const char* argv[])
1145 dev 175
{
176
	print_version();
1168 dev 177
	printf("\nA daemon which waits on specified UDP port for special");
1159 dev 178
	printf(" string (password) and reboots the computer.\n\n");
1164 dev 179
	printf("Usage: %s [--interface IP] [--port PORT] [--config CONFIG_FILE]\n", argv[0]);
1145 dev 180
	printf("   or: %s --version\n", argv[0]);
181
	printf("   or: %s --help\n\n", argv[0]);
1159 dev 182
	printf("Defaults are port 19 and config /etc/rebootd.conf.\n\n");
1145 dev 183
	printf("Config file looks like:\n--------------------------\n");
1164 dev 184
	printf("interface=192.168.0.1\nport=19\npassword=\"some password\"\n--------------------------\n\n");
1168 dev 185
	printf("Then run from any other host:\necho -n \"some password\" | nc -uo host_to_rebot 19\n");
1145 dev 186
}
187
 
1165 dev 188
static int print_error(const char *msg, const char *value)
189
{
190
	if(daemonized) {
191
		syslog(LOG_ERR, "%s", msg);
192
		if(value) syslog(LOG_ERR, " - %s\n", value);
193
		syslog(LOG_ERR, "\n");
194
	}
195
	else {
196
		fprintf(stderr, "%s", msg);
197
		if(value) fprintf(stderr, " - %s\n", value);
198
		fprintf(stderr, "\n");
199
	}
200
 
201
	return RESULT_ERROR;
202
}
203
 
1156 dev 204
static int print_cmd_error(int argc, const char* argv[], const char *msg, const char *value)
1145 dev 205
{
1140 dev 206
	fprintf(stderr, "%s", msg);
207
	if(value) fprintf(stderr, " - %s\n", value);
208
	fprintf(stderr, "\n");
209
 
1145 dev 210
	pring_usage(argc, argv);
211
 
212
	return RESULT_ERROR;
1140 dev 213
}
214
 
1156 dev 215
static int print_config_error(const char *config_name, int line, const char *msg, const char *value)
1140 dev 216
{
1165 dev 217
	if(daemonized) {
218
		syslog(LOG_ERR, "Error in %s, line %d: %s", config_name, line, msg);
219
		if(value) syslog(LOG_ERR, " - %s", value);
220
		syslog(LOG_ERR, "\n");
221
	}
222
	else {
223
		fprintf(stderr, "Error in %s, line %d: %s", config_name, line, msg);
224
		if(value) fprintf(stderr, " - %s", value);
225
		fprintf(stderr, "\n");
226
	}
1140 dev 227
 
1145 dev 228
	return RESULT_ERROR;
1140 dev 229
}
230
 
1165 dev 231
static int check_abs_path(const char *file_name)
232
{
233
	if(file_name && file_name[0] != '\0' && file_name[0] != '/') {
234
		return print_error("File must have an absolute path", file_name);
235
	}
236
 
237
	return RESULT_OK;
238
}
239
 
1156 dev 240
static int read_config(struct config *cfg, int argc, const char* argv[])
1140 dev 241
{
1165 dev 242
	int           res_cmd_line;
243
	int           res_config_file;
1163 dev 244
	struct config cmd_cfg;
245
	struct config file_cfg;
1140 dev 246
 
1164 dev 247
	memset(cfg, 0, sizeof(struct config));
1163 dev 248
	res_cmd_line = parse_cmd_line(&cmd_cfg, argc, argv);
1145 dev 249
	if(res_cmd_line != RESULT_OK) return res_cmd_line;
1165 dev 250
	if(check_abs_path(cmd_cfg.config_file) != RESULT_OK) return RESULT_ERROR;
1140 dev 251
 
1163 dev 252
	res_config_file = parse_config_file(&file_cfg,
253
		cmd_cfg.config_file[0] != '\0' ? cmd_cfg.config_file : DEFAULT_CFG_FILE);
1145 dev 254
	if(res_config_file != RESULT_OK) return res_config_file;
1140 dev 255
 
1165 dev 256
	if(file_cfg.password[0] == '\0')
257
		return print_error("Password is not set", NULL);
258
 
259
	/* save parsed values to general config */
260
	if(cmd_cfg.config_file[0] != '\0') {
261
		strncpy(cfg->config_file, cmd_cfg.config_file, sizeof(cfg->config_file));
262
		cfg->config_file_prio = CFG_PRIO_CMD;
1140 dev 263
	}
1165 dev 264
	else {
265
		strncpy(cfg->config_file, DEFAULT_CFG_FILE, sizeof(cfg->config_file));
266
		cfg->config_file_prio = CFG_PRIO_DEFAULT;
267
	}
1140 dev 268
 
1165 dev 269
	if(cmd_cfg.interface.s_addr) {
270
		cfg->interface      = cmd_cfg.interface;
271
		cfg->interface_prio = CFG_PRIO_CMD;
272
	}
273
	else if(file_cfg.interface.s_addr) {
274
		cfg->interface      = file_cfg.interface;
275
		cfg->interface_prio = CFG_PRIO_CONFIG;
276
	}
277
	else {
278
		cfg->interface_prio = CFG_PRIO_DEFAULT;
279
	}
280
 
281
	if(cmd_cfg.port) {
282
		cfg->port      = cmd_cfg.port;
283
		cfg->port_prio = CFG_PRIO_CMD;
284
	}
285
	else if(file_cfg.port) {
286
		cfg->port      = file_cfg.port;
287
		cfg->port_prio = CFG_PRIO_CONFIG;
288
	}
289
	else {
290
		cfg->port      = DEFAULT_PORT;
291
		cfg->port_prio = CFG_PRIO_DEFAULT;
292
	}
293
 
294
	if(cmd_cfg.pid_file[0] != '\0') {
295
		strncpy(cfg->pid_file, cmd_cfg.pid_file, sizeof(cfg->pid_file));
296
		cfg->pid_file_prio = CFG_PRIO_CMD;
297
	}
298
	else if(file_cfg.pid_file[0] != '\0') {
299
		strncpy(cfg->pid_file, file_cfg.pid_file, sizeof(cfg->pid_file));
300
		cfg->pid_file_prio = CFG_PRIO_CONFIG;
301
	}
302
	else {
303
		cfg->pid_file_prio = CFG_PRIO_DEFAULT;
304
	}
305
	if(check_abs_path(cfg->config_file) != RESULT_OK) return RESULT_ERROR;
306
 
307
	strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
308
	cfg->password_prio = CFG_PRIO_CONFIG;
309
 
310
	return RESULT_OK;
311
}
312
 
313
static int reread_config(struct config *cfg, int *reinit_needed)
314
{
315
	int           res_config_file;
316
	struct config file_cfg;
317
 
318
	*reinit_needed = 0;
319
 
320
	res_config_file = parse_config_file(&file_cfg, cfg->config_file);
321
	if(res_config_file != RESULT_OK) return res_config_file;
322
 
323
	if(file_cfg.password[0] == '\0')
324
		return print_error("Password is not set", NULL);
325
 
1163 dev 326
	/* save parsed values to general config */
1165 dev 327
	if(cfg->interface_prio >= CFG_PRIO_CONFIG && cfg->interface.s_addr != file_cfg.interface.s_addr)
328
	{
329
		*reinit_needed      = 1;
330
		cfg->interface      = file_cfg.interface;
331
		cfg->interface_prio = CFG_PRIO_CONFIG;
332
	}
1163 dev 333
 
1165 dev 334
	if(cfg->port_prio >= CFG_PRIO_CONFIG && cfg->port != file_cfg.port && file_cfg.port) {
335
		*reinit_needed = 1;
336
		cfg->port      = file_cfg.port;
337
		cfg->port_prio = CFG_PRIO_CONFIG;
338
	}
1164 dev 339
 
1165 dev 340
	if(check_abs_path(cfg->config_file) != RESULT_OK) return RESULT_ERROR;
1140 dev 341
 
1163 dev 342
	strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
1165 dev 343
	cfg->password_prio = CFG_PRIO_CONFIG;
1163 dev 344
 
1145 dev 345
	return RESULT_OK;
1140 dev 346
}
347
 
1164 dev 348
static int parse_interface(const char *s, char **end, struct in_addr *ip)
349
{
350
	char       buf[MAX_CONFIG_LINE];
351
	int        count;
352
	const char *c;
353
 
354
	c     = s;
355
	count = 0;
356
	while(c[0] != '\0' && !isspace(c[0])) c++, count++;
357
	if(count > MAX_CONFIG_LINE) return RESULT_ERROR;
358
	strncpy(buf, s, count);
359
	buf[count] = '\0';
360
	c++;
361
 
362
	if(end) *end = (char *)c;
363
 
364
	if(inet_aton(buf, ip) == 1)
365
		return RESULT_OK;
366
	else
367
		return RESULT_ERROR;
368
}
369
 
1163 dev 370
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[])
1140 dev 371
{
372
	char *end;
373
	int  i;
1163 dev 374
	long port;
1140 dev 375
 
1163 dev 376
	memset(cfg, 0, sizeof(struct config));
1140 dev 377
 
378
	for(i = 1; i < argc; i++) {
1165 dev 379
		if(0 == strcmp(argv[i], PARAM_INTERFACE)) {
1164 dev 380
			if(cfg->interface.s_addr)
381
				return print_cmd_error(argc, argv, "Interface is already set", NULL);
382
 
383
			if(++i < argc) {
384
				if(parse_interface(argv[i], (char **)NULL, &cfg->interface) != RESULT_OK)
385
					return print_cmd_error(argc, argv, 
386
						"Cannot parse interface", argv[i]);
387
			}
388
			else {
389
				return print_cmd_error(argc, argv, "Interface expected", NULL);
390
			}
391
		}
1165 dev 392
		else if(0 == strcmp(argv[i], PARAM_PORT)) {
1164 dev 393
			if(cfg->port)
1145 dev 394
				return print_cmd_error(argc, argv, "Port is already set", NULL);
1140 dev 395
 
396
			if(++i < argc) {
1163 dev 397
				port = strtol(argv[i], &end, 10);
398
				if(*end != '\0' || port < PORT_MIN || port > PORT_MAX)
1145 dev 399
					return print_cmd_error(argc, argv, 
400
						"Port number must be integer between 1 and 65535", NULL);
1163 dev 401
				cfg->port = (ushort)port;
1140 dev 402
			}
403
			else {
1145 dev 404
				return print_cmd_error(argc, argv, "Port number expected", NULL);
1140 dev 405
			}
406
		}
1165 dev 407
		else if(0 == strcmp(argv[i], PARAM_CONFIG)) {
1163 dev 408
			if(cfg->config_file[0] != '\0')
1165 dev 409
				return print_cmd_error(argc, argv, "Config file name is already set", NULL);
1140 dev 410
 
411
			if(++i < argc) {
1165 dev 412
				strncpy(cfg->config_file, argv[i], FILENAME_MAX);
413
				if(cfg->config_file[FILENAME_MAX - 1] != '\0')
1155 dev 414
					return print_cmd_error(argc, argv,
415
						"Config file name is too long", NULL);
1140 dev 416
			}
417
			else {
1165 dev 418
				return print_cmd_error(argc, argv, "Config file name expected", NULL);
1140 dev 419
			}
420
		}
1165 dev 421
		else if(0 == strcmp(argv[i], PARAM_PID_FILE)) {
422
			if(cfg->pid_file[0] != '\0')
423
				return print_cmd_error(argc, argv, "PID file name is already set", NULL);
424
 
425
			if(++i < argc) {
426
				strncpy(cfg->pid_file, argv[i], FILENAME_MAX);
427
				if(cfg->pid_file[FILENAME_MAX - 1] != '\0')
428
					return print_cmd_error(argc, argv,
429
						"PID file name is too long", NULL);
430
			}
431
			else {
432
				return print_cmd_error(argc, argv, "PID file name expected", NULL);
433
			}
434
		}
435
		else if(0 == strcmp(argv[i], PARAM_VERSION)) {
1145 dev 436
			print_version();
437
			return RESULT_EXIT;
438
		}
439
		else if(0 == strcmp(argv[i], PARAM_HELP_1) || 0 == strcmp(argv[i], PARAM_HELP_2)) {
440
			pring_usage(argc, argv);
441
			return RESULT_EXIT;
442
		}
1140 dev 443
		else {
1145 dev 444
			return print_cmd_error(argc, argv, "Unknown parameter", argv[i]);
1140 dev 445
		}
446
	}
447
 
1145 dev 448
	return RESULT_OK;
1140 dev 449
}
450
 
1164 dev 451
static int validate_equal_sign(const char *config_name, const int count, const char *line,
452
	uint name_len, char **subline)
453
{
454
	const char *c;
1140 dev 455
 
1164 dev 456
	c = line + name_len - 1;
457
	if('=' != c[0] && !isspace(c[0]))
458
		return print_config_error(config_name, count, "Unknown config parameter", line);
459
	while(c[0] != '\0' && isspace(c[0])) c++;
460
	if('=' != c[0])
461
		return print_config_error(config_name, count, "Equal sign expected", NULL);
462
	c++;
463
 
464
	if(subline) *subline = (char *)c;
465
 
466
	return RESULT_OK;
467
}
468
 
469
static int validate_eol(const char *config_name, const int count, const char *line)
470
{
471
	while(line[0] != '\0' && isspace(line[0])) line++;
472
	if('\0' != line[0] && '#' != line[0])
473
		return print_config_error(config_name, count, "End of line expected", NULL);
474
 
475
	return RESULT_OK;
476
}
477
 
1165 dev 478
static int extract_string_value(const char *config_name, const int count, char **subline, int must_quot,
479
	char *string, uint len)
1164 dev 480
{
481
	uint cur_len;
1165 dev 482
	int  quot;
1164 dev 483
 
484
	while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
1165 dev 485
	if('"' == *subline[0]) {
486
		quot = 1;
487
		(*subline)++;
488
	}
489
	else {
490
		if(must_quot) {
491
			return print_config_error(config_name, count, "Open quot expected", NULL);
492
		}
493
		else {
494
			quot = 0;
495
			/* skip spaces if not quoted */
496
			while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
497
		}
498
	}
1164 dev 499
 
500
	cur_len = 0;
1165 dev 501
	while(*subline[0] != '\0')
1164 dev 502
	{
1165 dev 503
		if(cur_len >= len) return print_config_error(config_name, count, "Value too long", NULL);
504
		if(quot && *subline[0] == '"') break;
505
		if(!quot && isspace(*subline[0])) break;
506
 
1164 dev 507
		string[0] = *subline[0];
508
		string++;
509
		(*subline)++;
510
		cur_len++;
511
	}
512
 
513
	string[0] = '\0';
1165 dev 514
	if(quot) {
515
		if('"' != *subline[0])
516
			return print_config_error(config_name, count, "Close quot expected", NULL);
517
		(*subline)++;
518
	}
1164 dev 519
 
520
	return RESULT_OK;
521
}
522
 
1163 dev 523
static int parse_config_file(struct config *cfg, const char *config_name)
1140 dev 524
{
525
	FILE *config_file;
526
	char buf[MAX_CONFIG_LINE];
527
	char *line;
528
	char *subline;
529
	int  count;
1156 dev 530
	uint len;
1163 dev 531
	long port;
1164 dev 532
	int  res;
1140 dev 533
 
1163 dev 534
	memset(cfg, 0, sizeof(struct config));
535
 
1140 dev 536
	config_file = fopen(config_name, "r");
1165 dev 537
	if(!config_file)
538
		return print_error("Can not open config file", strerror(errno));
1140 dev 539
 
540
	count = 0;
541
	while(fgets(buf, sizeof(buf), config_file)) {
542
		count++;
543
		line = buf;
544
 
545
		/* skip end spaces */
1156 dev 546
		len = strlen(line);
1146 dev 547
		if(len == MAX_CONFIG_LINE-1)
548
			return print_config_error(config_name, count, "Line is too long", NULL);
1140 dev 549
		while(len && isspace(line[len-1])) --len;
550
		if(!len) continue;
551
		line[len] = '\0';
552
 
553
		/* skip begin spaces */
554
		while(line[0] != '\0' && isspace(line[0])) line++;
555
 
556
		if('#' == line[0]) { /* skip comment lines */
557
			continue;
558
		}
1164 dev 559
		else if(strncmp(line, CONFIG_INTERFACE, min(sizeof(CONFIG_INTERFACE) - 1, len)) == 0) {
560
			if((res = validate_equal_sign(config_name, count, line,
561
				sizeof(CONFIG_INTERFACE), &subline)) != RESULT_OK) return res;
562
 
563
			if(parse_interface(subline, &subline, &cfg->interface) != RESULT_OK)
564
				return print_config_error(config_name, count,
565
					"Cannot parse interface", NULL);
566
 
567
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
568
		}
1140 dev 569
		else if(strncmp(line, CONFIG_PORT, min(sizeof(CONFIG_PORT) - 1, len)) == 0) {
1164 dev 570
			if((res = validate_equal_sign(config_name, count, line, sizeof(CONFIG_PORT),
571
				&subline)) != RESULT_OK) return res;
572
 
1163 dev 573
			port = strtol(subline, &subline, 10);
574
			if(port < PORT_MIN || port > PORT_MAX)
1140 dev 575
				return print_config_error(config_name, count, 
576
					"Port number must be integer between 1 and 65535", NULL);
1164 dev 577
 
578
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
1163 dev 579
			cfg->port = (ushort)port;
1140 dev 580
		}
581
		else if(strncmp(line, CONFIG_PASSWORD, min(sizeof(CONFIG_PASSWORD) - 1, len)) == 0) {
1164 dev 582
			if((res = validate_equal_sign(config_name, count, line,
583
				sizeof(CONFIG_PASSWORD), &subline)) != RESULT_OK) return res;
1140 dev 584
 
1165 dev 585
			if((res = extract_string_value(config_name, count, &subline, 1,
1164 dev 586
				cfg->password, sizeof(cfg->password))) != RESULT_OK) return res;
1140 dev 587
 
1164 dev 588
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
1140 dev 589
		}
1165 dev 590
		else if(strncmp(line, CONFIG_PID_FILE, min(sizeof(CONFIG_PID_FILE) - 1, len)) == 0) {
591
			if((res = validate_equal_sign(config_name, count, line,
592
				sizeof(CONFIG_PID_FILE), &subline)) != RESULT_OK) return res;
593
 
594
			if((res = extract_string_value(config_name, count, &subline, 0,
595
				cfg->pid_file, sizeof(cfg->pid_file))) != RESULT_OK) return res;
596
 
597
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
598
		}
1140 dev 599
		else {
600
			return print_config_error(config_name, count, "Unknown config parameter", line);
601
		}
602
	}
1164 dev 603
	if(ferror(config_file)) {
1165 dev 604
		print_error("Config file reading failed", strerror(errno));
1164 dev 605
	}
1140 dev 606
 
1165 dev 607
	if(fclose(config_file) != 0)
608
		return print_error("Can not close config file", strerror(errno));
1140 dev 609
 
1145 dev 610
	return RESULT_OK;
1140 dev 611
}
612
 
1156 dev 613
static int get_revision(void)
1145 dev 614
{
1156 dev 615
	int        r;
616
	const char *begin;
1145 dev 617
 
618
	begin = REVISION;
619
	while(begin[0] != '\0' && begin[0] != ':') begin++;
620
	if(begin[0] == '\0') return 0;
621
	begin++;
1156 dev 622
	r = (int)strtol(begin, (char**)NULL, 10);
1145 dev 623
 
624
	return r;
625
}
626
 
1165 dev 627
static int save_pid(const char *pid_file, const pid_t pid)
628
{
629
	int  fd;
630
	FILE *file;
631
 
632
	if(!pid_file || pid_file[0] == '\0') return RESULT_OK;
633
 
634
	unlink(pid_file);
635
 
636
	fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
637
	if(fd < 0) {
638
		syslog(LOG_ERR, "Can open PID file %s for write: %s\n", pid_file, strerror(errno));
639
		return RESULT_ERROR;
640
	}
641
 
642
	file = fdopen(fd, "w");
643
	if(!file) {
644
		syslog(LOG_ERR, "Can open PID file %s for write: %s\n", pid_file, strerror(errno));
645
		return RESULT_ERROR;
646
	}
647
 
648
	if(fprintf(file, "%d\n", pid) < 0) {
649
		syslog(LOG_ERR, "Can write PID to file %s: %s\n", pid_file, strerror(errno));
650
		return RESULT_ERROR;
651
	}
652
 
653
	if(fclose(file) != 0) {
654
		syslog(LOG_ERR, "Can not close PID file %s: %s\n", pid_file, strerror(errno));
655
		return RESULT_UNEXPECTED;
656
	}
657
 
658
	return RESULT_OK;
659
}
660
 
1156 dev 661
static int create_child(int soc)
1143 dev 662
{
663
	pid_t child;
664
 
665
	child = fork();
666
	if(child == -1) {
667
		fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
1145 dev 668
		return RESULT_UNEXPECTED; /* an unexpected error */
1143 dev 669
	}
670
	else if(child > 0) {
1156 dev 671
		if(close(soc) != 0) {
1143 dev 672
			fprintf(stderr, "Cannot close socket: %s\n", strerror(errno));
1145 dev 673
			return RESULT_UNEXPECTED; /* an unexpected error */
1143 dev 674
		}
1165 dev 675
 
1145 dev 676
		return RESULT_EXIT; /* we are the parent */
1143 dev 677
	}
678
	else {
1145 dev 679
		return RESULT_OK; /* we are the child */
1143 dev 680
	}
681
}
682
 
683
static int close_descr(int d)
684
{
685
	if(close(d) != 0) {
686
		syslog(LOG_ERR, "Cannot close descriptor %d: %s\n", d, strerror(errno));
1145 dev 687
		return RESULT_UNEXPECTED;
1143 dev 688
	}
1145 dev 689
	return RESULT_OK;
1143 dev 690
}
691
 
1165 dev 692
static void reconfig_signal(void)
693
{
694
	syslog(LOG_INFO, "reconfig");
695
	reconfig_needed = 1;
696
}
697
 
698
static void delete_pid_file(void)
699
{
700
	if(global_cfg.pid_file && global_cfg.pid_file[0] != '\0') {
701
		if(unlink(global_cfg.pid_file) != 0) {
702
			syslog(LOG_ERR, "Cannot delete PID file %s: %s\n",
703
				global_cfg.pid_file, strerror(errno));
704
		}
705
	}
706
}
707
 
708
static void quit_signal(void)
709
{
710
	delete_pid_file();
711
	syslog(LOG_WARNING, "quit");
712
	exit(0);
713
}
714
 
715
static void signal_handler(int sig)
716
{
717
	int saved_errno = errno;
718
 
719
	switch(sig) {
720
		case SIGHUP:
721
			reconfig_signal();
722
			break;
723
 
724
		case SIGINT:
725
		case SIGTERM:
726
		case SIGQUIT:
727
			quit_signal();
728
			break;
729
	}
730
 
731
	errno = saved_errno;
732
}
733
 
734
static int init_signal_handler(int sig)
735
{
736
	struct sigaction sa;
737
 
738
	sa.sa_flags   = 0;
739
	sa.sa_handler = signal_handler;
740
	sigemptyset(&sa.sa_mask);
741
 
742
	if(sigaction(sig, &sa, (struct sigaction *)NULL) != 0) {
743
		syslog(LOG_ERR, "Cannot register handler for signal %d: %s\n", sig, strerror(errno));
744
		return RESULT_UNEXPECTED;
745
	}
746
 
747
	return RESULT_OK;
748
}
749
 
750
static int init_signals(void)
751
{
752
	if(init_signal_handler(SIGHUP)  != RESULT_OK) return RESULT_UNEXPECTED;
753
	if(init_signal_handler(SIGINT)  != RESULT_OK) return RESULT_UNEXPECTED;
754
	if(init_signal_handler(SIGTERM) != RESULT_OK) return RESULT_UNEXPECTED;
755
	if(init_signal_handler(SIGQUIT) != RESULT_OK) return RESULT_UNEXPECTED;
756
 
757
	return RESULT_OK;
758
}
759
 
760
static void check_return(int res)
761
{
762
	if(daemonized && res != RESULT_OK) {
763
		delete_pid_file();
764
		syslog(LOG_WARNING, "quit");
765
	}
766
 
767
	switch(res) {
768
		case RESULT_EXIT:       exit(EXIT_OK);         return;  /* no error but exit */
769
		case RESULT_ERROR:      exit(EXIT_USER_ERROR); return;  /* user error */
770
		case RESULT_UNEXPECTED: exit(EXIT_UNEXPECTED); return;  /* unexpected error */
771
	}
772
}
773
 
1156 dev 774
int main(int argc, const char* argv[])
1140 dev 775
{
1165 dev 776
	int soc;
777
	int reinit_needed;
1140 dev 778
 
1143 dev 779
	/* get config */
1165 dev 780
	check_return(read_config(&global_cfg, argc, argv));
1143 dev 781
 
782
	/* try to listen the port */
1165 dev 783
	if((soc = establish(&global_cfg)) < 0) {
784
		fprintf(stderr, "Cannot listen to port %i\n", global_cfg.port);
1145 dev 785
		return EXIT_USER_ERROR;
1140 dev 786
	}
787
 
1143 dev 788
	/* fork and release the console */
1165 dev 789
	check_return(create_child(soc));
1140 dev 790
 
1143 dev 791
	/* continue as first child */
792
	if(setsid() == -1) {
793
		fprintf(stderr, "Cannot create session: %s\n", strerror(errno));
1145 dev 794
		return EXIT_UNEXPECTED;
1143 dev 795
	}
796
 
797
	/* fork the second time */
1165 dev 798
	check_return(create_child(soc));
799
 
800
	/* continue as final child */
801
	if(init_signals() != RESULT_OK) return EXIT_UNEXPECTED;
802
 
803
	if(chdir("/") < 0) {
804
		fprintf(stderr, "Cannot chdir to /: %s\n", strerror(errno));
805
		return EXIT_UNEXPECTED;
1143 dev 806
	}
1165 dev 807
	umask(0);
808
	check_return(save_pid(global_cfg.pid_file, getpid()));
809
	daemonized = 1;
1143 dev 810
 
1165 dev 811
	/* from now do not use console for error output */
1145 dev 812
	if(close_descr(0) != RESULT_OK) return EXIT_UNEXPECTED;
813
	if(close_descr(1) != RESULT_OK) return EXIT_UNEXPECTED;
814
	if(close_descr(2) != RESULT_OK) return EXIT_UNEXPECTED;
1143 dev 815
 
1165 dev 816
	for(;;) {
817
		syslog(LOG_INFO, "listen on %d", global_cfg.port);
818
		listen_socket(&global_cfg, soc);
1143 dev 819
 
1165 dev 820
		if(reconfig_needed) {
821
			reconfig_needed = 0;
822
			check_return(reread_config(&global_cfg, &reinit_needed));
823
			if(reinit_needed) {
824
				close(soc);
825
 
826
				if((soc = establish(&global_cfg)) < 0) {
827
					syslog(LOG_ERR, "Cannot listen to port %i\n", global_cfg.port);
828
					check_return(RESULT_ERROR);
829
				}
830
			}
831
		}
832
	}
833
 
834
	return EXIT_OK; /* unreacheable */
1140 dev 835
}
836