Subversion Repositories general

Rev

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