Projet

Général

Profil

Télécharger (21 ko) Statistiques
| Branche: | Révision:

univnautes-tools / pfPorts / check_reload_status / files / check_reload_status.c @ 453185f5

1
/*
2
        Copyright (C) 2010 Ermal Lu?i
3
        All rights reserved.
4

    
5
        Redistribution and use in source and binary forms, with or without
6
        modification, are permitted provided that the following conditions are met:
7

    
8
        1. Redistributions of source code must retain the above copyright notice,
9
           this list of conditions and the following disclaimer.
10

    
11
        2. Redistributions in binary form must reproduce the above copyright
12
           notice, this list of conditions and the following disclaimer in the
13
           documentation and/or other materials provided with the distribution.
14

    
15
        THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17
        AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18
        AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19
        OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
        SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
        INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
        CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
        POSSIBILITY OF SUCH DAMAGE.
25

    
26
*/
27

    
28
#include <sys/types.h>
29
#include <sys/event.h>
30
#include <sys/sbuf.h>
31
#include <sys/stat.h>
32
#include <sys/socket.h>
33
#include <sys/un.h>
34
#include <sys/queue.h>
35

    
36
#include <ctype.h>
37

    
38
#include <stdio.h>
39
#include <errno.h>
40
#include <err.h>
41
#include <fcntl.h>
42
#include <stdlib.h>
43
#include <signal.h>
44
#include <syslog.h>
45
#include <unistd.h>
46
#include <strings.h>
47
#include <string.h>
48

    
49
#include <event.h>
50

    
51
#include "server.h"
52
#include "common.h"
53

    
54
#include <sys/utsname.h>
55

    
56
#include "fastcgi.h"
57

    
58
/* function definitions */
59
static void			handle_signal(int);
60
static void			handle_signal_act(int, siginfo_t *, void *);
61
static void			run_command(struct command *, char *);
62
static void			set_blockmode(int socket, int cmd);
63
struct command *	match_command(struct command *target, char *wordpassed);
64
struct command *	parse_command(int fd, int argc, char **argv);
65
static void			socket_read_command(int socket, short event, void *arg);
66
static void			show_command_list(int fd, const struct command *list);
67
static void			socket_accept_command(int socket, short event, void *arg);
68
static void			socket_close_command(int fd, struct event *ev);
69
static void			socket_read_fcgi(int, short, void *);
70
static void			fcgi_send_command(int, short, void *);
71
static int			fcgi_open_socket(void);
72

    
73
/*
74
 * Internal representation of a packet.
75
 */
76
struct runq {
77
	TAILQ_ENTRY(runq) rq_link;
78
	struct event ev;
79
	char   command[2048];
80
	char   params[256];
81
	int requestId;
82
	int aggregate;
83
	int dontexec;
84
};
85
TAILQ_HEAD(runqueue, runq) cmds = TAILQ_HEAD_INITIALIZER(cmds);;
86

    
87
static pid_t ppid = -1;
88
static struct utsname uts;
89
static int fcgifd = -1;
90
static int keepalive = 1;
91
static char *fcgipath = (char *)FCGI_SOCK_PATH;
92
struct event fcgiev;
93

    
94
static int
95
prepare_packet(FCGI_Header *header, int type, int lcontent, int requestId)
96
{
97
        header->version = (unsigned char)FCGI_VERSION_1;
98
        header->type = (unsigned char)type;
99
        header->requestIdB1 = (unsigned char)((requestId >> 8) & 0xFF);
100
        header->requestIdB0 = (unsigned char)(requestId & 0xFF);
101
        header->contentLengthB1 = (unsigned char)((lcontent >> 8) & 0xFF);
102
        header->contentLengthB0 = (unsigned char)(lcontent & 0xFF);
103

    
104
        return (0);
105
}
106

    
107
static int
108
build_nvpair(struct sbuf *sb, int lkey, int lvalue, const char *key, char *svalue)
109
{
110
        if (lkey < 128)
111
                sbuf_putc(sb, lkey);
112
        else
113
                sbuf_printf(sb, "%c%c%c%c", (u_char)((lkey >> 24) | 0x80), (u_char)((lkey >> 16) & 0xFF), (u_char)((lkey >> 8) & 0xFF), (u_char)(lkey & 0xFF));
114

    
115
        if (lvalue < 128 || lvalue > 65535)
116
                sbuf_putc(sb, lvalue);
117
        else
118
                sbuf_printf(sb, "%c%c%c%c", (u_char)((lvalue >> 24) | 0x80), (u_char)((lvalue >> 16) & 0xFF), (u_char)((lvalue >> 8) & 0xFF), (u_char)(lvalue & 0xFF));
119

    
120
        if (lkey > 0)
121
                sbuf_printf(sb, "%s", key);
122
        if (lvalue > 0)
123
                sbuf_printf(sb, "%s", svalue);
124

    
125
        return (0);
126
}
127

    
128
static int
129
fcgi_open_socket()
130
{
131
        struct sockaddr_un sun;
132

    
133
	fcgifd = socket(PF_UNIX, SOCK_STREAM, 0);
134
	if (fcgifd < 0) {
135
		printf("Could not socket\n");
136
		return (-1);
137
	}
138

    
139
	unlink(fcgipath);
140
	bzero(&sun, sizeof(sun));
141
	sun.sun_family = PF_UNIX;
142
        strlcpy(sun.sun_path, fcgipath, sizeof(sun.sun_path));
143
        if (connect(fcgifd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
144
                printf("Could not bind\n");
145
                close(fcgifd);
146
                return (-1);
147
        }
148

    
149
        set_blockmode(fcgifd, O_NONBLOCK | FD_CLOEXEC);
150

    
151
	event_set(&fcgiev, fcgifd, EV_READ | EV_PERSIST, socket_read_fcgi, &fcgiev);
152
	event_add(&fcgiev, NULL);
153

    
154
	return (fcgifd);
155
}
156

    
157
static void
158
show_command_list(int fd, const struct command *list)
159
{
160
        int     i;
161
	char	value[2048];
162

    
163
	if (list == NULL)
164
		return;
165

    
166
        for (i = 0; list[i].action != NULLOPT; i++) {
167
                switch (list[i].type) {
168
                case NON:
169
			bzero(value, sizeof(value));
170
			snprintf(value, sizeof(value), "\t%s <cr>\n", list[i].keyword);
171
                        write(fd, value, strlen(value));
172
                        break;
173
                case COMPOUND:
174
			bzero(value, sizeof(value));
175
			snprintf(value, sizeof(value), "\t%s\n", list[i].keyword);
176
                        write(fd, value, strlen(value));
177
                        break;
178
                case ADDRESS:
179
			bzero(value, sizeof(value));
180
			snprintf(value, sizeof(value), "\t%s <address>\n", list[i].keyword);
181
                        write(fd, value, strlen(value));
182
                        break;
183
                case PREFIX:
184
			bzero(value, sizeof(value));
185
			snprintf(value, sizeof(value), "\t%s <address>[/len]\n", list[i].keyword);
186
                        write(fd, value, strlen(value));
187
                        break;
188
		case INTEGER:
189
			bzero(value, sizeof(value));
190
			snprintf(value, sizeof(value), "\t%s <number>\n", list[i].keyword);
191
                        write(fd, value, strlen(value));
192
			break;
193
                case IFNAME:
194
			bzero(value, sizeof(value));
195
			snprintf(value, sizeof(value), "\t%s <interface>\n", list[i].keyword);
196
                        write(fd, value, strlen(value));
197
                        break;
198
                case STRING:
199
			bzero(value, sizeof(value));
200
			snprintf(value, sizeof(value), "\t%s <string>\n", list[i].keyword);
201
                        write(fd, value, strlen(value));
202
                        break;
203
                }
204
        }
205
}
206

    
207
struct command *
208
parse_command(int fd, int argc, char **argv)
209
{
210
	struct command	*start = first_level;
211
	struct command	*match = NULL;
212
	char *errstring = (char *)"ERROR:\tvalid commands are:\n";
213

    
214
	while (argc >= 0) {
215
		match = match_command(start, *argv);
216
		if (match == NULL) {
217
			errstring = (char *)"ERROR:\tNo match found.\n";
218
			goto error3;
219
		}
220

    
221
		argc--;
222
		argv++;
223

    
224
		if (argc > 0 && match->next == NULL) {
225
			errstring = (char *)"ERROR:\textra arguments passed.\n";
226
			goto error3;
227
		}
228
		if (argc < 0 && match->type != NON) {
229
			if (match->next != NULL)
230
				start = match->next;
231
			errstring = (char *)"ERROR:\tincomplete command.\n";
232
			goto error3;
233
		}
234
		if (argc == 0 && *argv == NULL && match->type != NON) {
235
			if (match->next != NULL)
236
				start = match->next;
237
			errstring = (char *)"ERROR:\tincomplete command.\n";
238
			goto error3;
239
		}
240

    
241
		if ( match->next == NULL)
242
			break;
243

    
244
		start = match->next;	
245
	}
246

    
247
	return (match);
248
error3:
249
	write(fd, errstring, strlen(errstring));
250
	show_command_list(fd, start);
251
	return (NULL);
252
}
253

    
254
struct command *
255
match_command(struct command *target, char *wordpassed)
256
{
257
	int i;
258

    
259
	if (wordpassed == NULL)
260
		return NULL;
261

    
262
	for (i = 0; target[i].action != NULLOPT; i++) {
263
		if (strcmp(target[i].keyword, wordpassed) == 0)
264
			return &target[i];
265
	}
266

    
267
	return (NULL);
268
}
269

    
270
static void
271
handle_signal_act(int sig, siginfo_t *unused1 __unused, void *unused2 __unused)
272
{
273
	handle_signal(sig);
274
}
275

    
276
static void
277
handle_signal(int sig)
278
{
279
        switch(sig) {
280
        case SIGHUP:
281
        case SIGTERM:
282
#if 0
283
		if (child)
284
			exit(0);
285
#endif
286
                break;
287
        }
288
}
289

    
290
static void
291
fcgi_send_command(int fd __unused , short event __unused, void *arg)
292
{
293
	FCGI_BeginRequestRecord *bHeader;
294
        FCGI_Header *tmpl;
295
        struct sbuf sb;
296
	struct runq *cmd;
297
	struct timeval tv = { 8, 0 };
298
	static int requestId = 0;
299
	int len, result;
300
	char *p, sbuf[4096], buf[4096];
301

    
302
	cmd = arg;
303
	if (cmd == NULL)
304
		return;
305

    
306
	if (cmd->dontexec) {
307
		TAILQ_REMOVE(&cmds, cmd, rq_link);
308
		timeout_del(&cmd->ev);
309
		free(cmd);
310
		return;
311
	}
312

    
313
	requestId++;
314
	cmd->requestId = requestId;
315

    
316
	memset(sbuf, 0, sizeof(sbuf));
317
	sbuf_new(&sb, sbuf, 4096, 0);
318
	/* TODO: Use hardcoded length instead of strlen allover later on */
319
	/* TODO: Remove some env variables since might not be needed at all!!! */
320
	build_nvpair(&sb, strlen("GATEWAY_INTERFACE"), strlen("FastCGI/1.0"), "GATEWAY_INTERFACE", (char *)"FastCGI/1.0");
321
	build_nvpair(&sb, strlen("REQUEST_METHOD"), strlen("GET"), "REQUEST_METHOD", (char *)"GET");
322
	build_nvpair(&sb, strlen("SCRIPT_FILENAME"), strlen(cmd->command), "SCRIPT_FILENAME", cmd->command);
323
	build_nvpair(&sb, strlen("NO_HEADERS"), strlen("1"), "NO_HEADERS", (char *)"1");
324
	p = strrchr(cmd->command, '/');
325
	build_nvpair(&sb, strlen("SCRIPT_NAME"), strlen(p), "SCRIPT_NAME", p);
326
	p++;
327
	build_nvpair(&sb, strlen("DOCUMENT_URI"), strlen(p), "DOCUMENT_URI", p);
328
	build_nvpair(&sb, strlen("QUERY_STRING"), strlen(cmd->params), "QUERY_STRING", cmd->params);
329
	if (!cmd->params[0]) {
330
		build_nvpair(&sb, strlen("REQUEST_URI"), 0, "REQUEST_URI", p);
331
	} else {
332
		/* XXX: Hack in sight to avoid using another sbuf */
333
		build_nvpair(&sb, strlen("REQUEST_URI"), 1 + strlen(p) + strlen(cmd->params) + 1, "REQUEST_URI", (char *)"/");
334
		sbuf_printf(&sb, "%s?%s", p, cmd->params);
335
	}
336
	sbuf_finish(&sb);
337

    
338
	len = (3 * sizeof(FCGI_Header)) + sizeof(FCGI_BeginRequestRecord) + sbuf_len(&sb);
339
#if 0
340
	if (len > 4096) {
341
		buf = calloc(1, len);
342
		if (buf == NULL) {
343
			tv.tv_sec = 1;
344
			timeout_add(&cmd->ev, &tv);
345
			sbuf_delete(sbtmp2);
346
			return;
347
		}
348
	} else
349
#endif
350
		memset(buf, 0, sizeof(buf));
351

    
352
	bHeader = (FCGI_BeginRequestRecord *)buf;
353
	prepare_packet(&bHeader->header, FCGI_BEGIN_REQUEST, sizeof(bHeader->body), requestId);
354
	bHeader->body.roleB0 = (unsigned char)FCGI_RESPONDER;
355
	bHeader->body.flags = (unsigned char)(keepalive ? FCGI_KEEP_CONN : 0);
356
	bHeader++;
357
	tmpl = (FCGI_Header *)bHeader;
358
	prepare_packet(tmpl, FCGI_PARAMS, sbuf_len(&sb), requestId);
359
	tmpl++;
360
	memcpy((char *)tmpl, sbuf_data(&sb), sbuf_len(&sb));
361
	tmpl = (FCGI_Header *)(((char *)tmpl) + sbuf_len(&sb));
362
        prepare_packet(tmpl, FCGI_PARAMS, 0, requestId);
363
        tmpl++;
364
        prepare_packet(tmpl, FCGI_STDIN, 0, requestId);
365
	if (fcgifd < 0) {
366
		syslog(LOG_ERR, "Reopening fcgi socket");
367
		if (fcgi_open_socket() < 0) {
368
			/* Reschedule */
369
			tv.tv_sec = 1;
370
			timeout_add(&cmd->ev, &tv);
371
			return;
372
		}
373
	}
374

    
375
	result = write(fcgifd, buf, len);
376
	if (result < 0) {
377
		if (fcgifd)
378
			close(fcgifd);
379
		fcgifd = -1;
380
		syslog(LOG_ERR, "Something wrong happened while sending request: %m\n");
381
		timeout_add(&cmd->ev, &tv);
382
	} else if (cmd->aggregate > 0) {
383
		cmd->dontexec = 1;
384
		timeout_add(&cmd->ev, &tv);
385
	}
386
#if 0
387
	} else {
388
		TAILQ_REMOVE(&cmds, cmd, rq_link);
389
		timeout_del(&cmd->ev);
390
		free(cmd);
391
	}
392
#endif
393
}
394

    
395
static void
396
run_command_detailed(int fd __unused, short event __unused, void *arg) {
397
	struct runq *cmd;
398
	struct timeval tv = { 8, 0 };
399

    
400
	cmd = (struct runq *)arg;
401

    
402
	if (cmd == NULL)
403
		return;
404

    
405
	if (cmd->dontexec) {
406
		TAILQ_REMOVE(&cmds, cmd, rq_link);
407
		timeout_del(&cmd->ev);
408
		free(cmd);
409
		return;
410
	}
411

    
412

    
413
	switch (vfork()) {
414
	case -1:
415
		syslog(LOG_ERR, "Could not vfork() error %d - %s!!!", errno, strerror(errno));
416
		break;
417
	case 0:
418
		/* Possibly optimize by creating argument list and calling execve. */
419
		if (cmd->params[0])
420
			execl("/bin/sh", "/bin/sh", "-c", cmd->command, cmd->params, (char *)NULL);
421
		else
422
			execl("/bin/sh", "/bin/sh", "-c", cmd->command, (char *)NULL);
423
		syslog(LOG_ERR, "could not run: %s", cmd->command);
424
		_exit(127); /* Protect in case execl errors out */
425
		break;
426
	default:
427
		if (cmd->aggregate > 0) {
428
			cmd->dontexec = 1;
429
			timeout_add(&cmd->ev, &tv);
430
		} else {
431
			TAILQ_REMOVE(&cmds, cmd, rq_link);
432
			timeout_del(&cmd->ev);
433
			free(cmd);
434
		}
435
		break;
436
	}
437
}
438

    
439
static void
440
run_command(struct command *cmd, char *argv) {
441
	struct runq *command, *tmpcmd;
442
	struct timeval tv = { 1, 0 };
443
	int aggregate = 0;
444

    
445
	TAILQ_FOREACH(tmpcmd, &cmds, rq_link) {
446
		if (cmd->cmd.flags & AGGREGATE && !strcmp(tmpcmd->command, cmd->cmd.command)) {
447
			aggregate += tmpcmd->aggregate;
448
			if (aggregate > 1) {
449
				/* Rexec the command so the event is not lost. */
450
				if (tmpcmd->dontexec && aggregate < 3) {
451
					//syslog(LOG_ERR, "Rescheduling command %s", tmpcmd->command);
452
					syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
453
					tmpcmd->dontexec = 0;
454
					tv.tv_sec = 5;
455
					timeout_del(&tmpcmd->ev);
456
					timeout_add(&tmpcmd->ev, &tv);
457
				}
458
				return;
459
			}
460
		}
461
	}
462

    
463
	command = calloc(1, sizeof(*command));
464
	if (command == NULL) {
465
		syslog(LOG_ERR, "Calloc failure for command %s", argv);
466
		return;
467
	}
468

    
469
	command->aggregate = aggregate + 1;
470
	memcpy(command->command, cmd->cmd.command, sizeof(command->command));
471
	if (cmd->cmd.params)
472
		snprintf(command->params, sizeof(command->params), cmd->cmd.params, argv);
473

    
474
	if (!(cmd->cmd.flags & AGGREGATE))
475
		command->aggregate = 0;
476

    
477
	TAILQ_INSERT_HEAD(&cmds, command, rq_link);
478

    
479
	switch (cmd->type) {
480
	case NON:
481
		syslog(LOG_NOTICE, "%s", cmd->cmd.syslog);
482
		break;
483
	case COMPOUND: /* XXX: Should never happen. */
484
		syslog(LOG_ERR, "trying to execute COMPOUND entry!!! Please report it.");
485
		return;
486
		/* NOTREACHED */
487
		break;
488
	case ADDRESS:
489
	case PREFIX:
490
	case INTEGER:
491
	case IFNAME:
492
	case STRING:
493
		syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
494
		break;
495
	}
496

    
497
	if (cmd->cmd.flags & FCGICMD)
498
		timeout_set(&command->ev, fcgi_send_command, command);
499
	else
500
		timeout_set(&command->ev, run_command_detailed, command);
501
	timeout_add(&command->ev, &tv);
502

    
503
	return;
504
}
505

    
506
static void
507
socket_close_command(int fd, struct event *ev)
508
{
509
	event_del(ev);
510
	free(ev);
511
        close(fd);
512
}
513

    
514
static void
515
socket_read_fcgi(int fd, short event, void *arg __unused)
516
{
517
	struct runq *tmpcmd = NULL;
518
	FCGI_Header header;
519
	char buf[4096];
520
        int len, terr, success = 0;
521

    
522
	if (event == EV_TIMEOUT) {
523
		close(fd);
524
		fcgi_open_socket();
525
		return;
526
	}
527

    
528
	len = 0;
529
	memset(&header, 0, sizeof(header));
530
	if (recv(fd, &header, sizeof(header), 0) > 0) {
531
		len = (header.requestIdB1 << 8) | header.requestIdB0;
532
		TAILQ_FOREACH(tmpcmd, &cmds, rq_link) {
533
			if (tmpcmd->requestId == len)
534
				break;
535
		}
536
		len = (header.contentLengthB1 << 8) | header.contentLengthB0;
537
		len += header.paddingLength;
538
		
539
		//syslog(LOG_ERR, "LEN: %d, %d, %d\n", len, header.type, (header.requestIdB1 << 8) | header.requestIdB0);
540
		if (len > 0) {
541
			memset(buf, 0, sizeof(buf));
542

    
543
			/* XXX: Should check if len > sizeof(buf)? */
544
			terr = recv(fd, buf, len, 0);
545
			if (terr < 0) {
546
				//syslog(LOG_ERR, "Something happened during recv of data");
547
				return;
548
			}
549
		}
550
	} else 
551
		return;
552

    
553
	switch (header.type) {
554
	case FCGI_DATA:
555
	case FCGI_STDOUT:
556
	case FCGI_STDERR:
557
		break;
558
	case FCGI_ABORT_REQUEST:
559
		syslog(LOG_ERR, "Request aborted\n");
560
		break;
561
	case FCGI_END_REQUEST:
562
		if (len >= (int)sizeof(FCGI_EndRequestBody)) {
563
			switch (((FCGI_EndRequestBody *)buf)->protocolStatus) {
564
			case FCGI_CANT_MPX_CONN:
565
				syslog(LOG_ERR, "The FCGI server cannot multiplex\n");
566
				success = 0;
567
				break;
568
			case FCGI_OVERLOADED:
569
				syslog(LOG_ERR, "The FCGI server is overloaded\n");
570
				success = 0;
571
				break;
572
			case FCGI_UNKNOWN_ROLE:
573
				syslog(LOG_ERR, "FCGI role is unknown\n");
574
				success = 0;
575
				break;
576
			case FCGI_REQUEST_COMPLETE:
577
				//syslog(LOG_ERR, "FCGI request completed");
578
				success = 1;
579
				break;
580
			}
581
			if (tmpcmd != NULL)  {
582
				if (success) {
583
					TAILQ_REMOVE(&cmds, tmpcmd, rq_link);
584
					timeout_del(&tmpcmd->ev);
585
					free(tmpcmd);
586
				} else {
587
				       /* Rexec the command so the event is not lost. */
588
					syslog(LOG_ERR, "Repeating event %s/%s because it was not triggered.", tmpcmd->command, tmpcmd->params);
589
					if (tmpcmd->dontexec)
590
						tmpcmd->dontexec = 0;
591
				}
592
			}
593
		}
594
		break;
595
	}
596
}
597

    
598
static void
599
socket_read_command(int fd, short event, void *arg)
600
{
601
	struct command *cmd;
602
	struct event *ev = arg;
603
	enum { bufsize = 2048 };
604
	char buf[bufsize];
605
	register int n;
606
	char **ap, *argv[bufsize], *p;
607
	int i, loop = 0;
608

    
609
	if (event == EV_TIMEOUT) {
610
		socket_close_command(fd, ev);
611
		return;
612
	}
613
		
614
tryagain:
615
	bzero(buf, sizeof(buf));
616
	if ((n = read (fd, buf, bufsize)) == -1) {
617
		if (errno != EWOULDBLOCK && errno != EINTR) {
618
			return;
619
		} else {
620
			if (loop > 3) {
621
				return;
622
			}
623
			loop++;
624
			goto tryagain;
625
		}
626
	} else if (n == 0) {
627
		return;
628
	}
629
	
630
	if (buf[n - 1] == '\n')
631
		buf[n - 1] = '\0'; /* remove stray \n */
632
	if (n > 1 && buf[n - 2] == '\r') {
633
		n--;
634
		buf[n - 1] = '\0';
635
	}
636
	for (i = 0; i < n - 1; i++) {
637
		if (!isalpha(buf[i]) && !isspace(buf[i]) && !isdigit(buf[i]) && !ispunct(buf[i])) {
638
			write(fd, "ERROR:\tonly alphanumeric chars allowd", 37);
639
			socket_close_command(fd, ev);
640
			return;
641
		}
642
	}
643
	p = buf; /* blah, compiler workaround */
644

    
645
	i = 0;
646
	for (ap = argv; (*ap = strsep(&p, " \t")) != NULL;) {
647
		if (**ap != '\0') {
648
			if (++ap >= &argv[bufsize])
649
				break;
650
		}
651
		i++;
652
	}
653
	if (i > 0) {
654
		p = argv[i - 1];
655
		i = i - 1;
656
	} else {
657
		p = argv[i];
658
	}
659
	cmd = parse_command(fd, i, argv);
660
	if (cmd != NULL) {
661
		write(fd, "OK\n", 3);
662
		run_command(cmd, p);
663
	}
664

    
665
	return;
666
}
667

    
668
static void
669
socket_accept_command(int fd, __unused short event, __unused void *arg)
670
{
671
	struct sockaddr_un sun;
672
	struct timeval tv = { 10, 0 };
673
	struct event *ev;
674
	socklen_t len;
675
	int newfd;
676

    
677
	if ((newfd = accept(fd, (struct sockaddr *)&sun, &len)) < 0) {
678
		if (errno != EWOULDBLOCK && errno != EINTR)
679
			syslog(LOG_ERR, "problems on accept");
680
		return;
681
	}
682
	set_blockmode(newfd, O_NONBLOCK | FD_CLOEXEC);
683

    
684
	if ((ev = malloc(sizeof(*ev))) == NULL) {
685
		syslog(LOG_ERR, "Cannot allocate new struct event.");
686
		close(newfd);
687
		return;
688
	}
689

    
690
	event_set(ev, newfd, EV_READ | EV_PERSIST, socket_read_command, ev);
691
	event_add(ev, &tv);
692
}
693

    
694
static void
695
set_blockmode(int fd, int cmd)
696
{
697
        int     flags;
698

    
699
        if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
700
                errx(errno, "fcntl F_GETFL");
701

    
702
	flags |= cmd;
703

    
704
        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
705
                errx(errno, "fcntl F_SETFL");
706
}
707

    
708
int
709
main(void)
710
{
711
	struct event ev;
712
	struct sockaddr_un sun;
713
	struct sigaction sa;
714
	mode_t *mset, mode;
715
	sigset_t set;
716
	int fd, errcode = 0;
717
	char *p;
718

    
719
	tzset();
720

    
721
	/* daemonize */
722
	if (daemon(0, 0) < 0) {
723
		syslog(LOG_ERR, "check_reload_status could not start.");
724
		errcode = 1;
725
		goto error;
726
	}
727

    
728
	syslog(LOG_NOTICE, "check_reload_status is starting.");
729

    
730
	uname(&uts);
731

    
732
	if ((p = getenv("fcgipath")) != NULL) {
733
		fcgipath = p;
734
		syslog(LOG_ERR, "fcgipath %s", fcgipath);
735
	}
736

    
737
	sigemptyset(&set);
738
	sigfillset(&set);
739
	sigdelset(&set, SIGHUP);
740
	sigdelset(&set, SIGTERM);
741
	sigdelset(&set, SIGCHLD);
742
	sigprocmask(SIG_BLOCK, &set, NULL);
743
	signal(SIGCHLD, SIG_IGN);
744

    
745
	sa.sa_handler = handle_signal;
746
	sa.sa_sigaction = handle_signal_act;
747
        sa.sa_flags = SA_SIGINFO|SA_RESTART;
748
        sigemptyset(&sa.sa_mask);
749
        sigaction(SIGHUP, &sa, NULL);
750
	sigaction(SIGTERM, &sa, NULL);
751

    
752
	ppid = getpid();
753
	if (fork() == 0) {
754
		setproctitle("Monitoring daemon of check_reload_status");
755
		/* Prepare code to monitor the parent :) */
756
		struct kevent kev;
757
		int kq;
758

    
759
		while (1) {
760
			kq = kqueue();
761
			EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
762
			kevent(kq, &kev, 1, NULL, 0, NULL);
763
			switch (kevent(kq, NULL, 0, &kev, 1, NULL)) {
764
			case 1:
765
				syslog(LOG_ERR, "Reloading check_reload_status because it exited from an error!");
766
				execl("/usr/local/sbin/check_reload_status", "/usr/local/sbin/check_reload_status", (char *)NULL);
767
				_exit(127);
768
				syslog(LOG_ERR, "could not run check_reload_status again");
769
				/* NOTREACHED */
770
				break;
771
			default:
772
				/* XXX: Should report any event?! */
773
				break;
774
			}
775
			close(kq);
776
		}
777
		exit(2);
778
	}
779

    
780
	fd = socket(PF_UNIX, SOCK_STREAM, 0);
781
	if (fd < 0) {
782
		errcode = -1;
783
		printf("Could not socket\n");
784
		goto error;
785
	}
786

    
787
#if 0
788
	if (unlink(PATH) == -1) {
789
		errcode = -2;
790
		printf("Could not unlink\n");
791
		close(fd);
792
		goto error;
793
	}
794
#else
795
	unlink(PATH);
796
#endif
797

    
798
	bzero(&sun, sizeof(sun));
799
        sun.sun_family = PF_UNIX;
800
        strlcpy(sun.sun_path, PATH, sizeof(sun.sun_path));
801
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
802
		errcode = -2;
803
		printf("Could not bind\n");
804
		close(fd);
805
		goto error;
806
	}
807

    
808
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
809

    
810
        if (listen(fd, 30) == -1) {
811
                printf("control_listen: listen");
812
		close(fd);
813
                return (-1);
814
        }
815

    
816
	/* 0666 */
817
	if ((mset = setmode("0666")) != NULL) {
818
		mode = getmode(mset, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
819
		chmod(PATH, mode);
820
		free(mset);
821
	}
822

    
823
	TAILQ_INIT(&cmds);
824

    
825
	event_init();
826
	event_set(&ev, fd, EV_READ | EV_PERSIST, socket_accept_command, &ev);
827
	event_add(&ev, NULL);
828
	event_dispatch();
829

    
830
	return (0);
831
error:
832
	syslog(LOG_NOTICE, "check_reload_status is stopping.");
833

    
834
	return (errcode);
835
}
(1-1/6)