Projet

Général

Profil

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

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

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 = 1;
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("SCRIPT_FILENAME"), strlen(cmd->command), "SCRIPT_FILENAME", cmd->command);
324
	build_nvpair(&sb, strlen("NO_HEADERS"), strlen("1"), "NO_HEADERS", (char *)"1");
325
	p = strrchr(cmd->command, '/');
326
	build_nvpair(&sb, strlen("SCRIPT_NAME"), strlen(p), "SCRIPT_NAME", p);
327
	p++;
328
	build_nvpair(&sb, strlen("DOCUMENT_URI"), strlen(p), "DOCUMENT_URI", p);
329
	build_nvpair(&sb, strlen("QUERY_STRING"), strlen(cmd->params), "QUERY_STRING", cmd->params);
330
	if (!cmd->params[0]) {
331
		build_nvpair(&sb, strlen("REQUEST_URI"), 0, "REQUEST_URI", p);
332
	} else {
333
		/* XXX: Hack in sight to avoid using another sbuf */
334
		build_nvpair(&sb, strlen("REQUEST_URI"), 1 + strlen(p) + strlen(cmd->params) + 1, "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_Header);
360
	tmpl = (FCGI_Header *)bufptr;
361
	prepare_packet(tmpl, FCGI_PARAMS, sbuf_len(&sb), requestId);
362

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

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

    
371
	bufptr += sizeof(FCGI_Header);
372
	tmpl = (FCGI_Header *)bufptr;
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
			cmd->socket = -1;
379
			timeout_add(&cmd->ev, &tv);
380
			return;
381
		}
382
	}
383

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

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

    
411
	cmd = (struct runq *)arg;
412

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

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

    
423

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

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

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

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

    
480
	command->aggregate = aggregate + 1;
481
	memcpy(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
	TAILQ_INSERT_HEAD(&cmds, command, rq_link);
489

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

    
511
	if (cmd->cmd.flags & FCGICMD) {
512
		command->socket = fcgi_open_socket(command);
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

    
538
	if (event == EV_TIMEOUT) {
539
		close(fd);
540
		fcgi_open_socket(tmpcmd);
541
		return;
542
	}
543

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

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

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

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

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

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

    
678
	return;
679
}
680

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

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

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

    
703
	event_set(ev, newfd, EV_READ | EV_PERSIST, socket_read_command, ev);
704
	event_add(ev, &tv);
705
}
706

    
707
static void
708
set_blockmode(int fd, int cmd)
709
{
710
        int     flags;
711

    
712
        if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
713
                errx(errno, "fcntl F_GETFL");
714

    
715
	flags |= cmd;
716

    
717
        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
718
                errx(errno, "fcntl F_SETFL");
719
}
720

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

    
732
	tzset();
733

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

    
741
	syslog(LOG_NOTICE, "check_reload_status is starting.");
742

    
743
	uname(&uts);
744

    
745
	if ((p = getenv("fcgipath")) != NULL) {
746
		fcgipath = p;
747
		syslog(LOG_ERR, "fcgipath %s", fcgipath);
748
	}
749

    
750
	sigemptyset(&set);
751
	sigfillset(&set);
752
	sigdelset(&set, SIGHUP);
753
	sigdelset(&set, SIGTERM);
754
	sigdelset(&set, SIGCHLD);
755
	sigprocmask(SIG_BLOCK, &set, NULL);
756
	signal(SIGCHLD, SIG_IGN);
757

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

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

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

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

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

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

    
821
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
822

    
823
        if (listen(fd, 30) == -1) {
824
                printf("control_listen: listen");
825
		close(fd);
826
                return (-1);
827
        }
828

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

    
836
	TAILQ_INIT(&cmds);
837

    
838
	event_init();
839
	event_set(&ev, fd, EV_READ | EV_PERSIST, socket_accept_command, &ev);
840
	event_add(&ev, NULL);
841
	event_dispatch();
842

    
843
	return (0);
844
error:
845
	syslog(LOG_NOTICE, "check_reload_status is stopping.");
846

    
847
	return (errcode);
848
}
(1-1/6)