Subversion Repositories general

Rev

Rev 1163 | 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
 *
1145 dev 4
 * A daemon which waits on specified TCP 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):
18
 * echo -n "some password" | nc host_to_rebot 19
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>
34
#include <sys/types.h>
1144 dev 35
#include <sys/stat.h>
1140 dev 36
#include <sys/socket.h>
37
#include <sys/wait.h>
38
#include <sys/reboot.h>
39
#include <netinet/in.h>
40
#include <arpa/inet.h>
41
 
1145 dev 42
/* name version number */
1159 dev 43
#define APP_NAME          "rebootd"
1145 dev 44
#define VERSION           "1.0"
45
#define REVISION          "$Rev: 1164 $"
1144 dev 46
 
1145 dev 47
#define DEFAULT_PORT      19
1159 dev 48
#define DEFAULT_CFG_FILE  "/etc/rebootd.conf"
1145 dev 49
#define CMDSIZE           4096
50
#define BUFSIZE           4096
51
#define MAX_CONFIG_LINE   4096
52
#define PORT_MIN          1
53
#define PORT_MAX          65535
1140 dev 54
 
1145 dev 55
/* return values of functions */
56
#define RESULT_OK         0
57
#define RESULT_EXIT       1
58
#define RESULT_ERROR      2
59
#define RESULT_UNEXPECTED 3
1140 dev 60
 
1145 dev 61
/* return values for the whole program */
62
#define EXIT_OK           0
63
#define EXIT_USER_ERROR   1
64
#define EXIT_UNEXPECTED   2
65
 
66
/* command line and config file parameters */
67
#define PARAM_HELP_1      "-h"
68
#define PARAM_HELP_2      "--help"
69
#define PARAM_VERSION_1   "-v"
70
#define PARAM_VERSION_2   "--version"
1164 dev 71
#define PARAM_INTERFACE_1 "-i"
72
#define PARAM_INTERFACE_2 "--interface"
1145 dev 73
#define PARAM_PORT_1      "-p"
74
#define PARAM_PORT_2      "--port"
75
#define PARAM_CONFIG_1    "-c"
76
#define PARAM_CONFIG_2    "--config"
1164 dev 77
#define CONFIG_INTERFACE  "interface"
1145 dev 78
#define CONFIG_PORT       "port"
79
#define CONFIG_PASSWORD   "password"
80
 
1140 dev 81
struct config {
1164 dev 82
	char           config_file[FILENAME_MAX];
83
	struct in_addr interface;
84
	ushort         port;
85
	char           password[MAX_CONFIG_LINE];
1140 dev 86
};
87
 
1163 dev 88
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[]);
89
static int parse_config_file(struct config *cfg, const char *config_name);
1156 dev 90
static int get_revision(void);
1140 dev 91
 
1156 dev 92
static uint min(uint a, uint b)
1140 dev 93
{
94
	return (a < b) ? a : b;
95
}
96
 
1164 dev 97
static int establish(const struct config *cfg)
1140 dev 98
{
99
	int s;
100
	struct sockaddr_in sa;
101
 
102
	memset(&sa, 0, sizeof(struct sockaddr_in));
103
 
104
	sa.sin_family      = AF_INET;
1164 dev 105
	sa.sin_port        = htons(cfg->port);
106
	sa.sin_addr.s_addr = (cfg->interface.s_addr ? cfg->interface.s_addr : INADDR_ANY);
1140 dev 107
 
108
	if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
109
		return -1;
110
 
111
	if(bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
112
		close(s);
113
		return -1;
114
	}
115
 
1155 dev 116
	if(listen(s, 1) != 0) {
117
		close(s);
118
		return -1;
119
	}
1140 dev 120
 
121
	return s;
122
}
123
 
1156 dev 124
static void listen_socket(const struct config *cfg, int soc)
1142 dev 125
{
126
	int                t;
127
	char               cmd[CMDSIZE];
128
	char               buf[BUFSIZE];
129
	int                br;
130
	struct sockaddr_in sa;
131
	socklen_t          sa_len;
1155 dev 132
	int                cmdlen;
1142 dev 133
 
134
	for(;;) {
135
		sa_len = sizeof(sa);
1156 dev 136
		if((t = accept(soc, (struct sockaddr *)&sa, &sa_len)) < 0) {
1142 dev 137
			if(errno == EINTR) /* EINTR might happen on accept(), */
138
				continue;        /* try again */
139
 
1155 dev 140
			syslog(LOG_ERR, "cannot get connection, %s", strerror(errno));
1142 dev 141
			continue;
142
		}
143
 
1155 dev 144
		syslog(LOG_INFO, "connect from %s", inet_ntoa(sa.sin_addr));
1142 dev 145
 
146
		cmd[0] = '\0';
1155 dev 147
		cmdlen = 0;
1142 dev 148
		while((br = recv(t, buf, BUFSIZE, 0)) > 0) {
1156 dev 149
			strncat(cmd, buf, min((uint)br, sizeof(cmd) - cmdlen - 1));
150
			cmdlen += min((uint)br, sizeof(cmd) - cmdlen - 1);
1142 dev 151
		}
152
		sleep(1);
153
		close(t);
154
 
1147 dev 155
		syslog(LOG_INFO, "got command");
1142 dev 156
 
1143 dev 157
		if(0 == strncmp(cmd, cfg->password, sizeof(cmd))) {
1142 dev 158
			syslog(LOG_EMERG, "REBOOT");
159
			sleep(5);
160
			if(reboot(RB_AUTOBOOT) < 0) {
1155 dev 161
				syslog(LOG_ERR, "cannot reboot, %s",  strerror(errno));
1142 dev 162
			}
163
		}
164
	}
165
}
166
 
1156 dev 167
static void print_version(void)
1140 dev 168
{
1145 dev 169
	printf("%s %s.%d\n", APP_NAME, VERSION, get_revision());
170
}
171
 
1156 dev 172
static void pring_usage(int argc, const char* argv[])
1145 dev 173
{
174
	print_version();
1159 dev 175
	printf("\nA daemon which waits on specified TCP port for special");
176
	printf(" string (password) and reboots the computer.\n\n");
1164 dev 177
	printf("Usage: %s [--interface IP] [--port PORT] [--config CONFIG_FILE]\n", argv[0]);
1145 dev 178
	printf("   or: %s --version\n", argv[0]);
179
	printf("   or: %s --help\n\n", argv[0]);
1159 dev 180
	printf("Defaults are port 19 and config /etc/rebootd.conf.\n\n");
1145 dev 181
	printf("Config file looks like:\n--------------------------\n");
1164 dev 182
	printf("interface=192.168.0.1\nport=19\npassword=\"some password\"\n--------------------------\n\n");
1145 dev 183
	printf("Then run from any other host:\necho -n \"some password\" | nc host_to_rebot 19\n");
184
}
185
 
1156 dev 186
static int print_cmd_error(int argc, const char* argv[], const char *msg, const char *value)
1145 dev 187
{
1140 dev 188
	fprintf(stderr, "%s", msg);
189
	if(value) fprintf(stderr, " - %s\n", value);
190
	fprintf(stderr, "\n");
191
 
1145 dev 192
	pring_usage(argc, argv);
193
 
194
	return RESULT_ERROR;
1140 dev 195
}
196
 
1156 dev 197
static int print_config_error(const char *config_name, int line, const char *msg, const char *value)
1140 dev 198
{
199
	fprintf(stderr, "Error in %s, line %d: %s", config_name, line, msg);
200
	if(value) fprintf(stderr, " - %s", value);
201
	fprintf(stderr, "\n");
202
 
1145 dev 203
	return RESULT_ERROR;
1140 dev 204
}
205
 
1145 dev 206
/* return: 0 - no error, continue; 1 - no error, but exit; 2 - user error, exit; 3 - unexpected error, exit */
1156 dev 207
static int read_config(struct config *cfg, int argc, const char* argv[])
1140 dev 208
{
1163 dev 209
	int    res_cmd_line;
210
	int    res_config_file;
211
	struct config cmd_cfg;
212
	struct config file_cfg;
1140 dev 213
 
1164 dev 214
	memset(cfg, 0, sizeof(struct config));
1163 dev 215
	res_cmd_line = parse_cmd_line(&cmd_cfg, argc, argv);
1145 dev 216
	if(res_cmd_line != RESULT_OK) return res_cmd_line;
1140 dev 217
 
1163 dev 218
	res_config_file = parse_config_file(&file_cfg,
219
		cmd_cfg.config_file[0] != '\0' ? cmd_cfg.config_file : DEFAULT_CFG_FILE);
1145 dev 220
	if(res_config_file != RESULT_OK) return res_config_file;
1140 dev 221
 
1163 dev 222
	if(file_cfg.password[0] == '\0') {
1140 dev 223
		fprintf(stderr, "Password is not set\n");
1145 dev 224
		return RESULT_ERROR;
1140 dev 225
	}
226
 
1163 dev 227
	/* save parsed values to general config */
228
	strncpy(cfg->config_file, cmd_cfg.config_file, sizeof(cfg->config_file));
229
 
1164 dev 230
	if(cmd_cfg.interface.s_addr)
231
		cfg->interface = cmd_cfg.interface;
232
	else if(file_cfg.interface.s_addr)
233
		cfg->interface = file_cfg.interface;
234
 
1163 dev 235
	if(cmd_cfg.port > 0)
236
		cfg->port = cmd_cfg.port;
237
	else if(file_cfg.port > 0)
238
		cfg->port = file_cfg.port;
1140 dev 239
	else
1143 dev 240
		cfg->port = DEFAULT_PORT;
1140 dev 241
 
1163 dev 242
	strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
243
 
1145 dev 244
	return RESULT_OK;
1140 dev 245
}
246
 
1164 dev 247
static int parse_interface(const char *s, char **end, struct in_addr *ip)
248
{
249
	char       buf[MAX_CONFIG_LINE];
250
	int        count;
251
	const char *c;
252
 
253
	c     = s;
254
	count = 0;
255
	while(c[0] != '\0' && !isspace(c[0])) c++, count++;
256
	if(count > MAX_CONFIG_LINE) return RESULT_ERROR;
257
	strncpy(buf, s, count);
258
	buf[count] = '\0';
259
	c++;
260
 
261
	if(end) *end = (char *)c;
262
 
263
	if(inet_aton(buf, ip) == 1)
264
		return RESULT_OK;
265
	else
266
		return RESULT_ERROR;
267
}
268
 
1163 dev 269
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[])
1140 dev 270
{
271
	char *end;
272
	int  i;
1163 dev 273
	long port;
1140 dev 274
 
1163 dev 275
	memset(cfg, 0, sizeof(struct config));
1140 dev 276
 
277
	for(i = 1; i < argc; i++) {
1164 dev 278
		if(0 == strcmp(argv[i], PARAM_INTERFACE_1) || 0 == strcmp(argv[i], PARAM_INTERFACE_2)) {
279
			if(cfg->interface.s_addr)
280
				return print_cmd_error(argc, argv, "Interface is already set", NULL);
281
 
282
			if(++i < argc) {
283
				if(parse_interface(argv[i], (char **)NULL, &cfg->interface) != RESULT_OK)
284
					return print_cmd_error(argc, argv, 
285
						"Cannot parse interface", argv[i]);
286
			}
287
			else {
288
				return print_cmd_error(argc, argv, "Interface expected", NULL);
289
			}
290
		}
291
		else if(0 == strcmp(argv[i], PARAM_PORT_1) || 0 == strcmp(argv[i], PARAM_PORT_2)) {
292
			if(cfg->port)
1145 dev 293
				return print_cmd_error(argc, argv, "Port is already set", NULL);
1140 dev 294
 
295
			if(++i < argc) {
1163 dev 296
				port = strtol(argv[i], &end, 10);
297
				if(*end != '\0' || port < PORT_MIN || port > PORT_MAX)
1145 dev 298
					return print_cmd_error(argc, argv, 
299
						"Port number must be integer between 1 and 65535", NULL);
1163 dev 300
				cfg->port = (ushort)port;
1140 dev 301
			}
302
			else {
1145 dev 303
				return print_cmd_error(argc, argv, "Port number expected", NULL);
1140 dev 304
			}
305
		}
306
		else if(0 == strcmp(argv[i], PARAM_CONFIG_1) || 0 == strcmp(argv[i], PARAM_CONFIG_2)) {
1163 dev 307
			if(cfg->config_file[0] != '\0')
1145 dev 308
				return print_cmd_error(argc, argv, "Config file is already set", NULL);
1140 dev 309
 
310
			if(++i < argc) {
1163 dev 311
				strncpy(cfg->config_file, argv[i], MAX_CONFIG_LINE);
312
				if(cfg->config_file[MAX_CONFIG_LINE - 1] != '\0')
1155 dev 313
					return print_cmd_error(argc, argv,
314
						"Config file name is too long", NULL);
1140 dev 315
			}
316
			else {
1145 dev 317
				return print_cmd_error(argc, argv, "Config file expected", NULL);
1140 dev 318
			}
319
		}
1145 dev 320
		else if(0 == strcmp(argv[i], PARAM_VERSION_1) || 0 == strcmp(argv[i], PARAM_VERSION_2)) {
321
			print_version();
322
			return RESULT_EXIT;
323
		}
324
		else if(0 == strcmp(argv[i], PARAM_HELP_1) || 0 == strcmp(argv[i], PARAM_HELP_2)) {
325
			pring_usage(argc, argv);
326
			return RESULT_EXIT;
327
		}
1140 dev 328
		else {
1145 dev 329
			return print_cmd_error(argc, argv, "Unknown parameter", argv[i]);
1140 dev 330
		}
331
	}
332
 
1145 dev 333
	return RESULT_OK;
1140 dev 334
}
335
 
1164 dev 336
static int validate_equal_sign(const char *config_name, const int count, const char *line,
337
	uint name_len, char **subline)
338
{
339
	const char *c;
1140 dev 340
 
1164 dev 341
	c = line + name_len - 1;
342
	if('=' != c[0] && !isspace(c[0]))
343
		return print_config_error(config_name, count, "Unknown config parameter", line);
344
	while(c[0] != '\0' && isspace(c[0])) c++;
345
	if('=' != c[0])
346
		return print_config_error(config_name, count, "Equal sign expected", NULL);
347
	c++;
348
 
349
	if(subline) *subline = (char *)c;
350
 
351
	return RESULT_OK;
352
}
353
 
354
static int validate_eol(const char *config_name, const int count, const char *line)
355
{
356
	while(line[0] != '\0' && isspace(line[0])) line++;
357
	if('\0' != line[0] && '#' != line[0])
358
		return print_config_error(config_name, count, "End of line expected", NULL);
359
 
360
	return RESULT_OK;
361
}
362
 
363
static int extract_quoted(const char *config_name, const int count, char **subline, char *string, uint len)
364
{
365
	uint cur_len;
366
 
367
	while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
368
	if('"' != *subline[0])
369
		return print_config_error(config_name, count, "Open quot expected", NULL);
370
	(*subline)++;
371
 
372
	cur_len = 0;
373
	while(cur_len < len && *subline[0] != '\0' && *subline[0] != '"')
374
	{
375
		string[0] = *subline[0];
376
		string++;
377
		(*subline)++;
378
		cur_len++;
379
	}
380
 
381
	string[0] = '\0';
382
	if('"' != *subline[0])
383
		return print_config_error(config_name, count, "Close quot expected", NULL);
384
	(*subline)++;
385
 
386
	return RESULT_OK;
387
}
388
 
1163 dev 389
static int parse_config_file(struct config *cfg, const char *config_name)
1140 dev 390
{
391
	FILE *config_file;
392
	char buf[MAX_CONFIG_LINE];
393
	char *line;
394
	char *subline;
395
	int  count;
1156 dev 396
	uint len;
1163 dev 397
	long port;
1164 dev 398
	int  res;
1140 dev 399
 
1163 dev 400
	memset(cfg, 0, sizeof(struct config));
401
 
1140 dev 402
	config_file = fopen(config_name, "r");
403
	if(!config_file) {
404
		fprintf(stderr, "Can not open config file %s: %s\n", config_name, strerror(errno));
1145 dev 405
		return RESULT_ERROR;
1140 dev 406
	}
407
 
408
	count = 0;
409
	while(fgets(buf, sizeof(buf), config_file)) {
410
		count++;
411
		line = buf;
412
 
413
		/* skip end spaces */
1156 dev 414
		len = strlen(line);
1146 dev 415
		if(len == MAX_CONFIG_LINE-1)
416
			return print_config_error(config_name, count, "Line is too long", NULL);
1140 dev 417
		while(len && isspace(line[len-1])) --len;
418
		if(!len) continue;
419
		line[len] = '\0';
420
 
421
		/* skip begin spaces */
422
		while(line[0] != '\0' && isspace(line[0])) line++;
423
 
424
		if('#' == line[0]) { /* skip comment lines */
425
			continue;
426
		}
1164 dev 427
		else if(strncmp(line, CONFIG_INTERFACE, min(sizeof(CONFIG_INTERFACE) - 1, len)) == 0) {
428
			if((res = validate_equal_sign(config_name, count, line,
429
				sizeof(CONFIG_INTERFACE), &subline)) != RESULT_OK) return res;
430
 
431
			if(parse_interface(subline, &subline, &cfg->interface) != RESULT_OK)
432
				return print_config_error(config_name, count,
433
					"Cannot parse interface", NULL);
434
 
435
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
436
		}
1140 dev 437
		else if(strncmp(line, CONFIG_PORT, min(sizeof(CONFIG_PORT) - 1, len)) == 0) {
1164 dev 438
			if((res = validate_equal_sign(config_name, count, line, sizeof(CONFIG_PORT),
439
				&subline)) != RESULT_OK) return res;
440
 
1163 dev 441
			port = strtol(subline, &subline, 10);
442
			if(port < PORT_MIN || port > PORT_MAX)
1140 dev 443
				return print_config_error(config_name, count, 
444
					"Port number must be integer between 1 and 65535", NULL);
1164 dev 445
 
446
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
1163 dev 447
			cfg->port = (ushort)port;
1140 dev 448
		}
449
		else if(strncmp(line, CONFIG_PASSWORD, min(sizeof(CONFIG_PASSWORD) - 1, len)) == 0) {
1164 dev 450
			if((res = validate_equal_sign(config_name, count, line,
451
				sizeof(CONFIG_PASSWORD), &subline)) != RESULT_OK) return res;
1140 dev 452
 
1164 dev 453
			if((res = extract_quoted(config_name, count, &subline,
454
				cfg->password, sizeof(cfg->password))) != RESULT_OK) return res;
1140 dev 455
 
1164 dev 456
			if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
1140 dev 457
		}
458
		else {
459
			return print_config_error(config_name, count, "Unknown config parameter", line);
460
		}
461
	}
1164 dev 462
	if(ferror(config_file)) {
463
		fprintf(stderr, "Config file %s reading failed\n", config_name);
464
	}
1140 dev 465
 
466
	if(fclose(config_file) != 0) {
467
		fprintf(stderr, "Can not close config file %s: %s\n", config_name, strerror(errno));
1145 dev 468
		return RESULT_UNEXPECTED;
1140 dev 469
	}
470
 
1145 dev 471
	return RESULT_OK;
1140 dev 472
}
473
 
1156 dev 474
static int get_revision(void)
1145 dev 475
{
1156 dev 476
	int        r;
477
	const char *begin;
1145 dev 478
 
479
	begin = REVISION;
480
	while(begin[0] != '\0' && begin[0] != ':') begin++;
481
	if(begin[0] == '\0') return 0;
482
	begin++;
1156 dev 483
	r = (int)strtol(begin, (char**)NULL, 10);
1145 dev 484
 
485
	return r;
486
}
487
 
1156 dev 488
static int create_child(int soc)
1143 dev 489
{
490
	pid_t child;
491
 
492
	child = fork();
493
	if(child == -1) {
494
		fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
1145 dev 495
		return RESULT_UNEXPECTED; /* an unexpected error */
1143 dev 496
	}
497
	else if(child > 0) {
1156 dev 498
		if(close(soc) != 0) {
1143 dev 499
			fprintf(stderr, "Cannot close socket: %s\n", strerror(errno));
1145 dev 500
			return RESULT_UNEXPECTED; /* an unexpected error */
1143 dev 501
		}
1145 dev 502
		return RESULT_EXIT; /* we are the parent */
1143 dev 503
	}
504
	else {
1145 dev 505
		return RESULT_OK; /* we are the child */
1143 dev 506
	}
507
}
508
 
509
static int close_descr(int d)
510
{
511
	if(close(d) != 0) {
512
		syslog(LOG_ERR, "Cannot close descriptor %d: %s\n", d, strerror(errno));
1145 dev 513
		return RESULT_UNEXPECTED;
1143 dev 514
	}
1145 dev 515
	return RESULT_OK;
1143 dev 516
}
517
 
1156 dev 518
int main(int argc, const char* argv[])
1140 dev 519
{
1156 dev 520
	int           soc;
1143 dev 521
	struct config cfg;
1140 dev 522
 
1143 dev 523
	/* get config */
1145 dev 524
	switch(read_config(&cfg, argc, argv)) {
1156 dev 525
		case RESULT_EXIT:       return EXIT_OK;           /* no error but exit */
526
		case RESULT_ERROR:      return EXIT_USER_ERROR;   /* user error */
527
		case RESULT_UNEXPECTED: return EXIT_UNEXPECTED;   /* unexpected error */
1145 dev 528
	}
1143 dev 529
 
530
	/* try to listen the port */
1164 dev 531
	if((soc = establish(&cfg)) < 0) {
1140 dev 532
		fprintf(stderr, "Cannot listen to port %i\n", cfg.port);
1145 dev 533
		return EXIT_USER_ERROR;
1140 dev 534
	}
535
 
1143 dev 536
	/* fork and release the console */
1156 dev 537
	switch(create_child(soc)) {
538
		case RESULT_EXIT:       return EXIT_OK;           /* no error but exit */
539
		case RESULT_ERROR:      return EXIT_USER_ERROR;   /* user error */
540
		case RESULT_UNEXPECTED: return EXIT_UNEXPECTED;   /* unexpected error */
1143 dev 541
	}
1140 dev 542
 
1143 dev 543
	/* continue as first child */
544
	if(setsid() == -1) {
545
		fprintf(stderr, "Cannot create session: %s\n", strerror(errno));
1145 dev 546
		return EXIT_UNEXPECTED;
1143 dev 547
	}
548
 
549
	/* fork the second time */
1156 dev 550
	switch(create_child(soc)) {
551
		case RESULT_EXIT:       return EXIT_OK;           /* no error but exit */
552
		case RESULT_ERROR:      return EXIT_USER_ERROR;   /* user error */
553
		case RESULT_UNEXPECTED: return EXIT_UNEXPECTED;   /* unexpected error */
1143 dev 554
	}
555
 
556
	/* continue as final child, from now do not use console for error output */
557
	chdir("/");
558
	umask(0);
1145 dev 559
	if(close_descr(0) != RESULT_OK) return EXIT_UNEXPECTED;
560
	if(close_descr(1) != RESULT_OK) return EXIT_UNEXPECTED;
561
	if(close_descr(2) != RESULT_OK) return EXIT_UNEXPECTED;
1143 dev 562
 
563
	syslog(LOG_INFO, "listen on %d", cfg.port);
1156 dev 564
	listen_socket(&cfg, soc);
1143 dev 565
 
1156 dev 566
	return EXIT_OK; /* unreachedable */
1140 dev 567
}
568