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 @ 153aeb97

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

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

    
399
	cmd = (struct runq *)arg;
400

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

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

    
411

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

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

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

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

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

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

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

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

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

    
502
	return;
503
}
504

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

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

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

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

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

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

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

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

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

    
664
	return;
665
}
666

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

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

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

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

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

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

    
701
	flags |= cmd;
702

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

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

    
718
	tzset();
719

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

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

    
729
	uname(&uts);
730

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

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

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

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

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

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

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

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

    
807
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
808

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

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

    
822
	TAILQ_INIT(&cmds);
823

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

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

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