Projet

Général

Profil

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

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

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
		if (cmd->socket)
311
			close(cmd->socket);
312
		free(cmd);
313
		return;
314
	}
315

    
316
	requestId++;
317
	cmd->requestId = requestId;
318

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

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

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

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

    
365
	bufptr += sizeof(FCGI_Header);
366
	memcpy(bufptr, sbuf_data(&sb), sbuf_len(&sb));
367

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

    
372
	bufptr += sizeof(FCGI_Header);
373
	tmpl = (FCGI_Header *)bufptr;
374

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

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

    
409
static void
410
run_command_detailed(int fd __unused, short event __unused, void *arg) {
411
	struct runq *cmd;
412
	struct timeval tv = { 8, 0 };
413

    
414
	cmd = (struct runq *)arg;
415

    
416
	if (cmd == NULL)
417
		return;
418

    
419
	if (cmd->dontexec) {
420
		TAILQ_REMOVE(&cmds, cmd, rq_link);
421
		timeout_del(&cmd->ev);
422
		if (cmd->socket)
423
			close(cmd->socket);
424
		free(cmd);
425
		return;
426
	}
427

    
428

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

    
457
static void
458
run_command(struct command *cmd, char *argv) {
459
	struct runq *command, *tmpcmd;
460
	struct timeval tv = { 1, 0 };
461
	int aggregate = 0;
462

    
463
	TAILQ_FOREACH(tmpcmd, &cmds, rq_link) {
464
		if (cmd->cmd.flags & AGGREGATE && !strcmp(tmpcmd->command, cmd->cmd.command)) {
465
			aggregate += tmpcmd->aggregate;
466
			if (aggregate > 1) {
467
				/* Rexec the command so the event is not lost. */
468
				if (tmpcmd->dontexec && aggregate < 3) {
469
					//syslog(LOG_ERR, "Rescheduling command %s", tmpcmd->command);
470
					syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
471
					tmpcmd->dontexec = 0;
472
					tv.tv_sec = 5;
473
					timeout_del(&tmpcmd->ev);
474
					timeout_add(&tmpcmd->ev, &tv);
475
				}
476
				return;
477
			}
478
		}
479
	}
480

    
481
	command = calloc(1, sizeof(*command));
482
	if (command == NULL) {
483
		syslog(LOG_ERR, "Calloc failure for command %s", argv);
484
		return;
485
	}
486

    
487
	command->aggregate = aggregate + 1;
488
	//memcpy(command->command, cmd->cmd.command, sizeof(command->command));
489
	strlcpy(command->command, cmd->cmd.command, sizeof(command->command));
490
	if (cmd->cmd.params)
491
		snprintf(command->params, sizeof(command->params), cmd->cmd.params, argv);
492

    
493
	if (!(cmd->cmd.flags & AGGREGATE))
494
		command->aggregate = 0;
495

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

    
518
	TAILQ_INSERT_HEAD(&cmds, command, rq_link);
519

    
520
	if (cmd->cmd.flags & FCGICMD) {
521
		timeout_set(&command->ev, fcgi_send_command, command);
522
	} else {
523
		timeout_set(&command->ev, run_command_detailed, command);
524
	}
525
	timeout_add(&command->ev, &tv);
526

    
527
	return;
528
}
529

    
530
static void
531
socket_close_command(int fd, struct event *ev)
532
{
533
	event_del(ev);
534
	free(ev);
535
        close(fd);
536
}
537

    
538
static void
539
socket_read_fcgi(int fd, short event, void *arg)
540
{
541
	struct runq *tmpcmd = arg;
542
	FCGI_Header header;
543
	char buf[4096];
544
        int len, terr, success = 0;
545
	struct timeval tv = { 1, 0 };
546

    
547
	if (event == EV_TIMEOUT) {
548
		close(fd);
549
		syslog(LOG_ERR, "Rescheduling command %s due to timeout waiting for response", tmpcmd->command);
550
		tmpcmd->socket = fcgi_open_socket(tmpcmd);
551
		timeout_set(&tmpcmd->ev, fcgi_send_command, tmpcmd);
552
		timeout_add(&tmpcmd->ev, &tv);
553
		return;
554
	}
555

    
556
	len = 0;
557
	memset(&header, 0, sizeof(header));
558
	if (recv(fd, &header, sizeof(header), 0) > 0) {
559
		len = (header.requestIdB1 << 8) | header.requestIdB0;
560
		len = (header.contentLengthB1 << 8) | header.contentLengthB0;
561
		len += header.paddingLength;
562
		
563
		//syslog(LOG_ERR, "LEN: %d, %d, %d\n", len, header.type, (header.requestIdB1 << 8) | header.requestIdB0);
564
		if (len > 0) {
565
			memset(buf, 0, sizeof(buf));
566

    
567
			/* XXX: Should check if len > sizeof(buf)? */
568
			terr = recv(fd, buf, len, 0);
569
			if (terr < 0) {
570
				syslog(LOG_ERR, "Something happened during recv of data: %m");
571
				return;
572
			}
573
		}
574
	} else 
575
		return;
576

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

    
625
static void
626
socket_read_command(int fd, short event, void *arg)
627
{
628
	struct command *cmd;
629
	struct event *ev = arg;
630
	enum { bufsize = 2048 };
631
	char buf[bufsize];
632
	register int n;
633
	char **ap, *argv[bufsize], *p;
634
	int i, loop = 0;
635

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

    
672
	i = 0;
673
	for (ap = argv; (*ap = strsep(&p, " \t")) != NULL;) {
674
		if (**ap != '\0') {
675
			if (++ap >= &argv[bufsize])
676
				break;
677
		}
678
		i++;
679
	}
680
	if (i > 0) {
681
		p = argv[i - 1];
682
		i = i - 1;
683
	} else {
684
		p = argv[i];
685
	}
686
	cmd = parse_command(fd, i, argv);
687
	if (cmd != NULL) {
688
		write(fd, "OK\n", 3);
689
		run_command(cmd, p);
690
	}
691

    
692
	return;
693
}
694

    
695
static void
696
socket_accept_command(int fd, __unused short event, __unused void *arg)
697
{
698
	struct sockaddr_un sun;
699
	struct timeval tv = { 10, 0 };
700
	struct event *ev;
701
	socklen_t len;
702
	int newfd;
703

    
704
	if ((newfd = accept(fd, (struct sockaddr *)&sun, &len)) < 0) {
705
		if (errno != EWOULDBLOCK && errno != EINTR)
706
			syslog(LOG_ERR, "problems on accept");
707
		return;
708
	}
709
	set_blockmode(newfd, O_NONBLOCK | FD_CLOEXEC);
710

    
711
	if ((ev = malloc(sizeof(*ev))) == NULL) {
712
		syslog(LOG_ERR, "Cannot allocate new struct event.");
713
		close(newfd);
714
		return;
715
	}
716

    
717
	event_set(ev, newfd, EV_READ | EV_PERSIST, socket_read_command, ev);
718
	event_add(ev, &tv);
719
}
720

    
721
static void
722
set_blockmode(int fd, int cmd)
723
{
724
        int     flags;
725

    
726
        if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
727
                errx(errno, "fcntl F_GETFL");
728

    
729
	flags |= cmd;
730

    
731
        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
732
                errx(errno, "fcntl F_SETFL");
733
}
734

    
735
int
736
main(void)
737
{
738
	struct event ev;
739
	struct sockaddr_un sun;
740
	struct sigaction sa;
741
	mode_t *mset, mode;
742
	sigset_t set;
743
	int fd, errcode = 0;
744
	char *p;
745

    
746
	tzset();
747

    
748
	/* daemonize */
749
	if (daemon(0, 0) < 0) {
750
		syslog(LOG_ERR, "check_reload_status could not start.");
751
		errcode = 1;
752
		goto error;
753
	}
754

    
755
	syslog(LOG_NOTICE, "check_reload_status is starting.");
756

    
757
	uname(&uts);
758

    
759
	if ((p = getenv("fcgipath")) != NULL) {
760
		fcgipath = p;
761
		syslog(LOG_NOTICE, "fcgipath from environment %s", fcgipath);
762
	}
763

    
764
	sigemptyset(&set);
765
	sigfillset(&set);
766
	sigdelset(&set, SIGHUP);
767
	sigdelset(&set, SIGTERM);
768
	sigdelset(&set, SIGCHLD);
769
	sigprocmask(SIG_BLOCK, &set, NULL);
770
	signal(SIGCHLD, SIG_IGN);
771

    
772
	sa.sa_handler = handle_signal;
773
	sa.sa_sigaction = handle_signal_act;
774
        sa.sa_flags = SA_SIGINFO|SA_RESTART;
775
        sigemptyset(&sa.sa_mask);
776
        sigaction(SIGHUP, &sa, NULL);
777
	sigaction(SIGTERM, &sa, NULL);
778

    
779
	ppid = getpid();
780
	if (fork() == 0) {
781
		setproctitle("Monitoring daemon of check_reload_status");
782
		/* Prepare code to monitor the parent :) */
783
		struct kevent kev;
784
		int kq;
785

    
786
		while (1) {
787
			kq = kqueue();
788
			EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
789
			kevent(kq, &kev, 1, NULL, 0, NULL);
790
			switch (kevent(kq, NULL, 0, &kev, 1, NULL)) {
791
			case 1:
792
				syslog(LOG_ERR, "Reloading check_reload_status because it exited from an error!");
793
				execl("/usr/local/sbin/check_reload_status", "/usr/local/sbin/check_reload_status", (char *)NULL);
794
				_exit(127);
795
				syslog(LOG_ERR, "could not run check_reload_status again");
796
				/* NOTREACHED */
797
				break;
798
			default:
799
				/* XXX: Should report any event?! */
800
				break;
801
			}
802
			close(kq);
803
		}
804
		exit(2);
805
	}
806

    
807
	fd = socket(PF_UNIX, SOCK_STREAM, 0);
808
	if (fd < 0) {
809
		errcode = -1;
810
		printf("Could not socket\n");
811
		goto error;
812
	}
813

    
814
#if 0
815
	if (unlink(PATH) == -1) {
816
		errcode = -2;
817
		printf("Could not unlink\n");
818
		close(fd);
819
		goto error;
820
	}
821
#else
822
	unlink(PATH);
823
#endif
824

    
825
	bzero(&sun, sizeof(sun));
826
        sun.sun_family = PF_UNIX;
827
        strlcpy(sun.sun_path, PATH, sizeof(sun.sun_path));
828
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
829
		errcode = -2;
830
		printf("Could not bind\n");
831
		close(fd);
832
		goto error;
833
	}
834

    
835
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
836

    
837
        if (listen(fd, 30) == -1) {
838
                printf("control_listen: listen");
839
		close(fd);
840
                return (-1);
841
        }
842

    
843
	/* 0666 */
844
	if ((mset = setmode("0666")) != NULL) {
845
		mode = getmode(mset, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
846
		chmod(PATH, mode);
847
		free(mset);
848
	}
849

    
850
	TAILQ_INIT(&cmds);
851

    
852
	event_init();
853
	event_set(&ev, fd, EV_READ | EV_PERSIST, socket_accept_command, &ev);
854
	event_add(&ev, NULL);
855
	event_dispatch();
856

    
857
	return (0);
858
error:
859
	syslog(LOG_NOTICE, "check_reload_status is stopping.");
860

    
861
	return (errcode);
862
}
(1-1/6)