Projet

Général

Profil

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

univnautes-tools / pfPorts / check_reload_status / files / check_reload_status.c @ ea59ab58

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
/*
59
 * Internal representation of a packet.
60
 */
61
struct runq {
62
	TAILQ_ENTRY(runq) rq_link;
63
	struct event ev;
64
	char   command[2048];
65
	char   params[256];
66
	int requestId;
67
	int aggregate;
68
	int dontexec;
69
	int socket;
70
	struct event socket_ev;
71
};
72
TAILQ_HEAD(runqueue, runq) cmds = TAILQ_HEAD_INITIALIZER(cmds);;
73

    
74
/* function definitions */
75
static void			handle_signal(int);
76
static void			handle_signal_act(int, siginfo_t *, void *);
77
static void			run_command(struct command *, char *);
78
static void			set_blockmode(int socket, int cmd);
79
struct command *	match_command(struct command *target, char *wordpassed);
80
struct command *	parse_command(int fd, int argc, char **argv);
81
static void			socket_read_command(int socket, short event, void *arg);
82
static void			show_command_list(int fd, const struct command *list);
83
static void			socket_accept_command(int socket, short event, void *arg);
84
static void			socket_close_command(int fd, struct event *ev);
85
static void			socket_read_fcgi(int, short, void *);
86
static void			fcgi_send_command(int, short, void *);
87
static int			fcgi_open_socket(struct runq *);
88

    
89
static pid_t ppid = -1;
90
static struct utsname uts;
91
static int keepalive = 0;
92
static char *fcgipath = (char *)FCGI_SOCK_PATH;
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(struct runq *cmd)
130
{
131
        struct sockaddr_un sun;
132
	int fcgifd;
133

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

    
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
                syslog(LOG_ERR, "Could not connect to %s\n", fcgipath);
145
                close(fcgifd);
146
                return (-1);
147
        }
148

    
149
        set_blockmode(fcgifd, O_NONBLOCK | FD_CLOEXEC);
150

    
151
	event_set(&cmd->socket_ev, fcgifd, EV_READ | EV_PERSIST, socket_read_fcgi, cmd);
152
	event_add(&cmd->socket_ev, 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], *bufptr;
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
		event_del(&cmd->socket_ev);
310
		free(cmd);
311
		return;
312
	}
313

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

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

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

    
353
	bufptr = buf;
354
	bHeader = (FCGI_BeginRequestRecord *)buf;
355
	prepare_packet(&bHeader->header, FCGI_BEGIN_REQUEST, sizeof(bHeader->body), requestId);
356
	bHeader->body.roleB0 = (unsigned char)FCGI_RESPONDER;
357
	bHeader->body.flags = (unsigned char)(keepalive ? FCGI_KEEP_CONN : 0);
358

    
359
	bufptr += sizeof(FCGI_BeginRequestRecord);
360
	tmpl = (FCGI_Header *)bufptr;
361
	prepare_packet(tmpl, FCGI_PARAMS, sbuf_len(&sb), requestId);
362

    
363
	bufptr += sizeof(FCGI_Header);
364
	memcpy(bufptr, sbuf_data(&sb), sbuf_len(&sb));
365

    
366
	bufptr += sbuf_len(&sb);
367
	tmpl = (FCGI_Header *)bufptr;
368
        prepare_packet(tmpl, FCGI_PARAMS, 0, requestId);
369

    
370
	bufptr += sizeof(FCGI_Header);
371
	tmpl = (FCGI_Header *)bufptr;
372

    
373
        prepare_packet(tmpl, FCGI_STDIN, 0, requestId);
374
	if (cmd->socket < 0) {
375
		if ((cmd->socket = fcgi_open_socket(cmd)) < 0) {
376
			/* Reschedule */
377
			tv.tv_sec = 1;
378
			timeout_add(&cmd->ev, &tv);
379
			return;
380
		}
381
	}
382

    
383
	result = write(cmd->socket, buf, len);
384
	if (result < 0) {
385
		if (cmd->socket) {
386
			event_del(&cmd->socket_ev);
387
			close(cmd->socket);
388
		}
389
		cmd->socket = -1;
390
		syslog(LOG_ERR, "Something wrong happened while sending request: %m\n");
391
		timeout_add(&cmd->ev, &tv);
392
	} else if (cmd->aggregate > 0) {
393
		cmd->dontexec = 1;
394
		timeout_add(&cmd->ev, &tv);
395
	}
396
#if 0
397
	} else {
398
		TAILQ_REMOVE(&cmds, cmd, rq_link);
399
		timeout_del(&cmd->ev);
400
		free(cmd);
401
	}
402
#endif
403
}
404

    
405
static void
406
run_command_detailed(int fd __unused, short event __unused, void *arg) {
407
	struct runq *cmd;
408
	struct timeval tv = { 8, 0 };
409

    
410
	cmd = (struct runq *)arg;
411

    
412
	if (cmd == NULL)
413
		return;
414

    
415
	if (cmd->dontexec) {
416
		TAILQ_REMOVE(&cmds, cmd, rq_link);
417
		timeout_del(&cmd->ev);
418
		free(cmd);
419
		return;
420
	}
421

    
422

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

    
449
static void
450
run_command(struct command *cmd, char *argv) {
451
	struct runq *command, *tmpcmd;
452
	struct timeval tv = { 1, 0 };
453
	int aggregate = 0;
454

    
455
	TAILQ_FOREACH(tmpcmd, &cmds, rq_link) {
456
		if (cmd->cmd.flags & AGGREGATE && !strcmp(tmpcmd->command, cmd->cmd.command)) {
457
			aggregate += tmpcmd->aggregate;
458
			if (aggregate > 1) {
459
				/* Rexec the command so the event is not lost. */
460
				if (tmpcmd->dontexec && aggregate < 3) {
461
					//syslog(LOG_ERR, "Rescheduling command %s", tmpcmd->command);
462
					syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
463
					tmpcmd->dontexec = 0;
464
					tv.tv_sec = 5;
465
					timeout_del(&tmpcmd->ev);
466
					timeout_add(&tmpcmd->ev, &tv);
467
				}
468
				return;
469
			}
470
		}
471
	}
472

    
473
	command = calloc(1, sizeof(*command));
474
	if (command == NULL) {
475
		syslog(LOG_ERR, "Calloc failure for command %s", argv);
476
		return;
477
	}
478

    
479
	command->aggregate = aggregate + 1;
480
	//memcpy(command->command, cmd->cmd.command, sizeof(command->command));
481
	strlcpy(command->command, cmd->cmd.command, sizeof(command->command));
482
	if (cmd->cmd.params)
483
		snprintf(command->params, sizeof(command->params), cmd->cmd.params, argv);
484

    
485
	if (!(cmd->cmd.flags & AGGREGATE))
486
		command->aggregate = 0;
487

    
488
	switch (cmd->type) {
489
	case NON:
490
		syslog(LOG_NOTICE, "%s", cmd->cmd.syslog);
491
		break;
492
	case COMPOUND: /* XXX: Should never happen. */
493
		syslog(LOG_ERR, "trying to execute COMPOUND entry!!! Please report it.");
494
		free(command);
495
		return;
496
		/* NOTREACHED */
497
		break;
498
	case ADDRESS:
499
	case PREFIX:
500
	case INTEGER:
501
	case IFNAME:
502
	case STRING:
503
		if (argv != NULL)
504
			syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
505
		else
506
			syslog(LOG_NOTICE, "%s", cmd->cmd.syslog);
507
		break;
508
	}
509

    
510
	TAILQ_INSERT_HEAD(&cmds, command, rq_link);
511

    
512
	if (cmd->cmd.flags & FCGICMD) {
513
		timeout_set(&command->ev, fcgi_send_command, command);
514
	} else {
515
		timeout_set(&command->ev, run_command_detailed, command);
516
	}
517
	timeout_add(&command->ev, &tv);
518

    
519
	return;
520
}
521

    
522
static void
523
socket_close_command(int fd, struct event *ev)
524
{
525
	event_del(ev);
526
	free(ev);
527
        close(fd);
528
}
529

    
530
static void
531
socket_read_fcgi(int fd, short event, void *arg)
532
{
533
	struct runq *tmpcmd = arg;
534
	FCGI_Header header;
535
	char buf[4096];
536
        int len, terr, success = 0;
537
	struct timeval tv = { 1, 0 };
538

    
539
	if (event == EV_TIMEOUT) {
540
		close(fd);
541
		syslog(LOG_ERR, "Rescheduling command %s due to timeout waiting for response", tmpcmd->command);
542
		tmpcmd->socket = fcgi_open_socket(tmpcmd);
543
		timeout_set(&tmpcmd->ev, fcgi_send_command, tmpcmd);
544
		timeout_add(&tmpcmd->ev, &tv);
545
		return;
546
	}
547

    
548
	len = 0;
549
	memset(&header, 0, sizeof(header));
550
	if (recv(fd, &header, sizeof(header), 0) > 0) {
551
		len = (header.requestIdB1 << 8) | header.requestIdB0;
552
		len = (header.contentLengthB1 << 8) | header.contentLengthB0;
553
		len += header.paddingLength;
554
		
555
		//syslog(LOG_ERR, "LEN: %d, %d, %d\n", len, header.type, (header.requestIdB1 << 8) | header.requestIdB0);
556
		if (len > 0) {
557
			memset(buf, 0, sizeof(buf));
558

    
559
			/* XXX: Should check if len > sizeof(buf)? */
560
			terr = recv(fd, buf, len, 0);
561
			if (terr < 0) {
562
				syslog(LOG_ERR, "Something happened during recv of data: %m");
563
				return;
564
			}
565
		}
566
	} else 
567
		return;
568

    
569
	switch (header.type) {
570
	case FCGI_DATA:
571
	case FCGI_STDOUT:
572
	case FCGI_STDERR:
573
		break;
574
	case FCGI_ABORT_REQUEST:
575
		syslog(LOG_ERR, "Request aborted\n");
576
		break;
577
	case FCGI_END_REQUEST:
578
		if (len >= (int)sizeof(FCGI_EndRequestBody)) {
579
			switch (((FCGI_EndRequestBody *)buf)->protocolStatus) {
580
			case FCGI_CANT_MPX_CONN:
581
				syslog(LOG_ERR, "The FCGI server cannot multiplex\n");
582
				success = 0;
583
				break;
584
			case FCGI_OVERLOADED:
585
				syslog(LOG_ERR, "The FCGI server is overloaded\n");
586
				success = 0;
587
				break;
588
			case FCGI_UNKNOWN_ROLE:
589
				syslog(LOG_ERR, "FCGI role is unknown\n");
590
				success = 0;
591
				break;
592
			case FCGI_REQUEST_COMPLETE:
593
				//syslog(LOG_ERR, "FCGI request completed");
594
				success = 1;
595
				break;
596
			}
597
			if (tmpcmd != NULL)  {
598
				if (success) {
599
					TAILQ_REMOVE(&cmds, tmpcmd, rq_link);
600
					timeout_del(&tmpcmd->ev);
601
					event_del(&tmpcmd->socket_ev);
602
					free(tmpcmd);
603
				} else {
604
				       /* Rexec the command so the event is not lost. */
605
					syslog(LOG_ERR, "Repeating event %s/%s because it was not triggered.", tmpcmd->command, tmpcmd->params);
606
					if (tmpcmd->dontexec)
607
						tmpcmd->dontexec = 0;
608
				}
609
			}
610
		}
611
		break;
612
	}
613
}
614

    
615
static void
616
socket_read_command(int fd, short event, void *arg)
617
{
618
	struct command *cmd;
619
	struct event *ev = arg;
620
	enum { bufsize = 2048 };
621
	char buf[bufsize];
622
	register int n;
623
	char **ap, *argv[bufsize], *p;
624
	int i, loop = 0;
625

    
626
	if (event == EV_TIMEOUT) {
627
		socket_close_command(fd, ev);
628
		return;
629
	}
630
		
631
tryagain:
632
	bzero(buf, sizeof(buf));
633
	if ((n = read (fd, buf, bufsize)) == -1) {
634
		if (errno != EWOULDBLOCK && errno != EINTR) {
635
			return;
636
		} else {
637
			if (loop > 3) {
638
				return;
639
			}
640
			loop++;
641
			goto tryagain;
642
		}
643
	} else if (n == 0) {
644
		return;
645
	}
646
	
647
	if (buf[n - 1] == '\n')
648
		buf[n - 1] = '\0'; /* remove stray \n */
649
	if (n > 1 && buf[n - 2] == '\r') {
650
		n--;
651
		buf[n - 1] = '\0';
652
	}
653
	for (i = 0; i < n - 1; i++) {
654
		if (!isalpha(buf[i]) && !isspace(buf[i]) && !isdigit(buf[i]) && !ispunct(buf[i])) {
655
			write(fd, "ERROR:\tonly alphanumeric chars allowd", 37);
656
			socket_close_command(fd, ev);
657
			return;
658
		}
659
	}
660
	p = buf; /* blah, compiler workaround */
661

    
662
	i = 0;
663
	for (ap = argv; (*ap = strsep(&p, " \t")) != NULL;) {
664
		if (**ap != '\0') {
665
			if (++ap >= &argv[bufsize])
666
				break;
667
		}
668
		i++;
669
	}
670
	if (i > 0) {
671
		p = argv[i - 1];
672
		i = i - 1;
673
	} else {
674
		p = argv[i];
675
	}
676
	cmd = parse_command(fd, i, argv);
677
	if (cmd != NULL) {
678
		write(fd, "OK\n", 3);
679
		run_command(cmd, p);
680
	}
681

    
682
	return;
683
}
684

    
685
static void
686
socket_accept_command(int fd, __unused short event, __unused void *arg)
687
{
688
	struct sockaddr_un sun;
689
	struct timeval tv = { 10, 0 };
690
	struct event *ev;
691
	socklen_t len;
692
	int newfd;
693

    
694
	if ((newfd = accept(fd, (struct sockaddr *)&sun, &len)) < 0) {
695
		if (errno != EWOULDBLOCK && errno != EINTR)
696
			syslog(LOG_ERR, "problems on accept");
697
		return;
698
	}
699
	set_blockmode(newfd, O_NONBLOCK | FD_CLOEXEC);
700

    
701
	if ((ev = malloc(sizeof(*ev))) == NULL) {
702
		syslog(LOG_ERR, "Cannot allocate new struct event.");
703
		close(newfd);
704
		return;
705
	}
706

    
707
	event_set(ev, newfd, EV_READ | EV_PERSIST, socket_read_command, ev);
708
	event_add(ev, &tv);
709
}
710

    
711
static void
712
set_blockmode(int fd, int cmd)
713
{
714
        int     flags;
715

    
716
        if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
717
                errx(errno, "fcntl F_GETFL");
718

    
719
	flags |= cmd;
720

    
721
        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
722
                errx(errno, "fcntl F_SETFL");
723
}
724

    
725
int
726
main(void)
727
{
728
	struct event ev;
729
	struct sockaddr_un sun;
730
	struct sigaction sa;
731
	mode_t *mset, mode;
732
	sigset_t set;
733
	int fd, errcode = 0;
734
	char *p;
735

    
736
	tzset();
737

    
738
	/* daemonize */
739
	if (daemon(0, 0) < 0) {
740
		syslog(LOG_ERR, "check_reload_status could not start.");
741
		errcode = 1;
742
		goto error;
743
	}
744

    
745
	syslog(LOG_NOTICE, "check_reload_status is starting.");
746

    
747
	uname(&uts);
748

    
749
	if ((p = getenv("fcgipath")) != NULL) {
750
		fcgipath = p;
751
		syslog(LOG_NOTICE, "fcgipath from environment %s", fcgipath);
752
	}
753

    
754
	sigemptyset(&set);
755
	sigfillset(&set);
756
	sigdelset(&set, SIGHUP);
757
	sigdelset(&set, SIGTERM);
758
	sigdelset(&set, SIGCHLD);
759
	sigprocmask(SIG_BLOCK, &set, NULL);
760
	signal(SIGCHLD, SIG_IGN);
761

    
762
	sa.sa_handler = handle_signal;
763
	sa.sa_sigaction = handle_signal_act;
764
        sa.sa_flags = SA_SIGINFO|SA_RESTART;
765
        sigemptyset(&sa.sa_mask);
766
        sigaction(SIGHUP, &sa, NULL);
767
	sigaction(SIGTERM, &sa, NULL);
768

    
769
	ppid = getpid();
770
	if (fork() == 0) {
771
		setproctitle("Monitoring daemon of check_reload_status");
772
		/* Prepare code to monitor the parent :) */
773
		struct kevent kev;
774
		int kq;
775

    
776
		while (1) {
777
			kq = kqueue();
778
			EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
779
			kevent(kq, &kev, 1, NULL, 0, NULL);
780
			switch (kevent(kq, NULL, 0, &kev, 1, NULL)) {
781
			case 1:
782
				syslog(LOG_ERR, "Reloading check_reload_status because it exited from an error!");
783
				execl("/usr/local/sbin/check_reload_status", "/usr/local/sbin/check_reload_status", (char *)NULL);
784
				_exit(127);
785
				syslog(LOG_ERR, "could not run check_reload_status again");
786
				/* NOTREACHED */
787
				break;
788
			default:
789
				/* XXX: Should report any event?! */
790
				break;
791
			}
792
			close(kq);
793
		}
794
		exit(2);
795
	}
796

    
797
	fd = socket(PF_UNIX, SOCK_STREAM, 0);
798
	if (fd < 0) {
799
		errcode = -1;
800
		printf("Could not socket\n");
801
		goto error;
802
	}
803

    
804
#if 0
805
	if (unlink(PATH) == -1) {
806
		errcode = -2;
807
		printf("Could not unlink\n");
808
		close(fd);
809
		goto error;
810
	}
811
#else
812
	unlink(PATH);
813
#endif
814

    
815
	bzero(&sun, sizeof(sun));
816
        sun.sun_family = PF_UNIX;
817
        strlcpy(sun.sun_path, PATH, sizeof(sun.sun_path));
818
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
819
		errcode = -2;
820
		printf("Could not bind\n");
821
		close(fd);
822
		goto error;
823
	}
824

    
825
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
826

    
827
        if (listen(fd, 30) == -1) {
828
                printf("control_listen: listen");
829
		close(fd);
830
                return (-1);
831
        }
832

    
833
	/* 0666 */
834
	if ((mset = setmode("0666")) != NULL) {
835
		mode = getmode(mset, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
836
		chmod(PATH, mode);
837
		free(mset);
838
	}
839

    
840
	TAILQ_INIT(&cmds);
841

    
842
	event_init();
843
	event_set(&ev, fd, EV_READ | EV_PERSIST, socket_accept_command, &ev);
844
	event_add(&ev, NULL);
845
	event_dispatch();
846

    
847
	return (0);
848
error:
849
	syslog(LOG_NOTICE, "check_reload_status is stopping.");
850

    
851
	return (errcode);
852
}
(1-1/6)