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 @ 9882a4c5

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

    
148
        set_blockmode(fcgifd, O_NONBLOCK | FD_CLOEXEC);
149

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

    
153
	return (fcgifd);
154
}
155

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

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

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

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

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

    
220
		argc--;
221
		argv++;
222

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

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

    
243
		start = match->next;	
244
	}
245

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

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

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

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

    
266
	return (NULL);
267
}
268

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

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

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

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

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

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

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

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

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

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

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

    
401
	cmd = (struct runq *)arg;
402

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

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

    
413

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

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

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

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

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

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

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

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

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

    
504
	return;
505
}
506

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

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

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

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

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

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

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

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

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

    
666
	return;
667
}
668

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

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

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

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

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

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

    
703
	flags |= cmd;
704

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

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

    
720
	tzset();
721

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

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

    
731
	uname(&uts);
732

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

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

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

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

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

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

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

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

    
809
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
810

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

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

    
824
	TAILQ_INIT(&cmds);
825

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

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

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