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 @ bcfab93f

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) & 0xFF), (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) & 0xFF), (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
	if (!cmd->params[0])
328
		build_nvpair(&sb, strlen("REQUEST_URI"), strlen(p), "REQUEST_URI", p);
329
	build_nvpair(&sb, strlen("DOCUMENT_URI"), strlen(p), "DOCUMENT_URI", p);
330
	if (cmd->params[0]) {
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
	if (cmd->cmd.params)
482
		snprintf(command->params, sizeof(command->params), cmd->cmd.params, argv);
483

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

    
487
	TAILQ_INSERT_HEAD(&cmds, command, rq_link);
488

    
489
	switch (cmd->type) {
490
	case NON:
491
		syslog(LOG_NOTICE, "%s", cmd->cmd.syslog);
492
		break;
493
	case COMPOUND: /* XXX: Should never happen. */
494
		syslog(LOG_ERR, "trying to execute COMPOUND entry!!! Please report it.");
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
	if (cmd->cmd.flags & FCGICMD) {
511
		command->socket = fcgi_open_socket(command);
512
		timeout_set(&command->ev, fcgi_send_command, command);
513
	} else {
514
		timeout_set(&command->ev, run_command_detailed, command);
515
	}
516
	timeout_add(&command->ev, &tv);
517

    
518
	return;
519
}
520

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

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

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

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

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

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

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

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

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

    
681
	return;
682
}
683

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

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

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

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

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

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

    
718
	flags |= cmd;
719

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

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

    
735
	tzset();
736

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

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

    
746
	uname(&uts);
747

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

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

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

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

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

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

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

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

    
824
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
825

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

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

    
839
	TAILQ_INIT(&cmds);
840

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

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

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