• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/lighttpd-1.4.39/src/
1//#include "log.h"
2#include <string.h>
3#include <sys/wait.h>
4#include <stdlib.h>
5#include <stdio.h>
6#include <string.h>
7#include <errno.h>
8#include <unistd.h>
9#include <time.h>
10#include <signal.h>
11
12#ifdef EMBEDDED_EANBLE
13#ifndef APP_IPKG
14#include <utils.h>
15#include <shutils.h>
16#include <shared.h>
17#endif
18#include "nvram_control.h"
19#endif
20#ifdef APP_IPKG
21/*pids()*/
22#include<sys/types.h>
23#include <dirent.h>
24#include <ctype.h>
25#include <stddef.h>
26enum {
27        PSSCAN_PID      = 1 << 0,
28        PSSCAN_PPID     = 1 << 1,
29        PSSCAN_PGID     = 1 << 2,
30        PSSCAN_SID      = 1 << 3,
31        PSSCAN_UIDGID   = 1 << 4,
32        PSSCAN_COMM     = 1 << 5,
33        /* PSSCAN_CMD      = 1 << 6, - use read_cmdline instead */
34        PSSCAN_ARGV0    = 1 << 7,
35        /* PSSCAN_EXE      = 1 << 8, - not implemented */
36        PSSCAN_STATE    = 1 << 9,
37        PSSCAN_VSZ      = 1 << 10,
38        PSSCAN_RSS      = 1 << 11,
39        PSSCAN_STIME    = 1 << 12,
40        PSSCAN_UTIME    = 1 << 13,
41        PSSCAN_TTY      = 1 << 14,
42        PSSCAN_SMAPS    = (1 << 15) * 0,
43        PSSCAN_ARGVN    = (1 << 16) * 1,
44        PSSCAN_START_TIME = 1 << 18,
45        /* These are all retrieved from proc/NN/stat in one go: */
46        PSSCAN_STAT     = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
47                        | PSSCAN_COMM | PSSCAN_STATE
48                        | PSSCAN_VSZ | PSSCAN_RSS
49                        | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME
50                        | PSSCAN_TTY,
51};
52
53#define PROCPS_BUFSIZE 1024
54
55static int read_to_buf(const char *filename, void *buf)
56{
57        int fd;
58        /* open_read_close() would do two reads, checking for EOF.
59         * When you have 10000 /proc/$NUM/stat to read, it isn't desirable */
60        int ret = -1;
61        fd = open(filename, O_RDONLY);
62        if (fd >= 0) {
63                ret = read(fd, buf, PROCPS_BUFSIZE-1);
64                close(fd);
65        }
66        ((char *)buf)[ret > 0 ? ret : 0] = '\0';
67        return ret;
68}
69
70void* xzalloc(size_t size)
71{
72        void *ptr = malloc(size);
73        memset(ptr, 0, size);
74        return ptr;
75}
76
77void* xrealloc(void *ptr, size_t size)
78{
79        ptr = realloc(ptr, size);
80        if (ptr == NULL && size != 0)
81                perror("no memory");
82        return ptr;
83}
84
85void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx)
86{
87        int mask = 1 << (unsigned char)sizeof_and_shift;
88
89        if (!(idx & (mask - 1))) {
90                sizeof_and_shift >>= 8; /* sizeof(vector[0]) */
91                vector = xrealloc(vector, sizeof_and_shift * (idx + mask + 1));
92                memset((char*)vector + (sizeof_and_shift * idx), 0, sizeof_and_shift * (mask + 1));
93        }
94        return vector;
95}
96
97#define xrealloc_vector(vector, shift, idx) \
98        xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx))
99
100typedef struct procps_status_t {
101        DIR *dir;
102        unsigned char shift_pages_to_bytes;
103        unsigned char shift_pages_to_kb;
104/* Fields are set to 0/NULL if failed to determine (or not requested) */
105        unsigned int argv_len;
106        char *argv0;
107        /* Everything below must contain no ptrs to malloc'ed data:
108         * it is memset(0) for each process in procps_scan() */
109        unsigned long vsz, rss; /* we round it to kbytes */
110        unsigned long stime, utime;
111        unsigned long start_time;
112        unsigned pid;
113        unsigned ppid;
114        unsigned pgid;
115        unsigned sid;
116        unsigned uid;
117        unsigned gid;
118        unsigned tty_major,tty_minor;
119        char state[4];
120        /* basename of executable in exec(2), read from /proc/N/stat
121         * (if executable is symlink or script, it is NOT replaced
122         * by link target or interpreter name) */
123        char comm[16];
124        /* user/group? - use passwd/group parsing functions */
125} procps_status_t;
126
127        static procps_status_t* alloc_procps_scan(void)
128        {
129            unsigned n = getpagesize();
130            procps_status_t* sp = xzalloc(sizeof(procps_status_t));
131            sp->dir = opendir("/proc");
132            while (1) {
133                n >>= 1;
134                if (!n) break;
135                sp->shift_pages_to_bytes++;
136            }
137            sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
138            return sp;
139        }
140        void BUG_comm_size(void)
141        {
142        }
143#define ULLONG_MAX     (~0ULL)
144#define UINT_MAX       (~0U)
145
146static unsigned long long ret_ERANGE(void)
147{
148        errno = ERANGE; /* this ain't as small as it looks (on glibc) */
149        return ULLONG_MAX;
150}
151static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr)
152{
153    if (endp) *endp = endptr;
154
155    /* errno is already set to ERANGE by strtoXXX if value overflowed */
156    if (endptr[0]) {
157        /* "1234abcg" or out-of-range? */
158        if (isalnum(endptr[0]) || errno)
159            return ret_ERANGE();
160        /* good number, just suspicious terminator */
161        errno = EINVAL;
162    }
163    return v;
164}
165unsigned bb_strtou(const char *arg, char **endp, int base)
166{
167    unsigned long v;
168    char *endptr;
169
170    if (!isalnum(arg[0])) return ret_ERANGE();
171    errno = 0;
172    v = strtoul(arg, &endptr, base);
173    if (v > UINT_MAX) return ret_ERANGE();
174    return handle_errors(v, endp, endptr);
175}
176
177const char* bb_basename(const char *name)
178{
179        const char *cp = strrchr(name, '/');
180        if (cp)
181                return cp + 1;
182        return name;
183}
184
185static int comm_match(procps_status_t *p, const char *procName)
186{
187        int argv1idx;
188
189        /* comm does not match */
190        if (strncmp(p->comm, procName, 15) != 0)
191                return 0;
192
193        /* in Linux, if comm is 15 chars, it may be a truncated */
194        if (p->comm[14] == '\0') /* comm is not truncated - match */
195                return 1;
196
197        /* comm is truncated, but first 15 chars match.
198         * This can be crazily_long_script_name.sh!
199         * The telltale sign is basename(argv[1]) == procName. */
200
201        if (!p->argv0)
202                return 0;
203
204        argv1idx = strlen(p->argv0) + 1;
205        if (argv1idx >= p->argv_len)
206                return 0;
207
208        if (strcmp(bb_basename(p->argv0 + argv1idx), procName) != 0)
209                return 0;
210
211        return 1;
212}
213
214void free_procps_scan(procps_status_t* sp)
215{
216        closedir(sp->dir);
217        free(sp->argv0);
218        free(sp);
219}
220
221procps_status_t* procps_scan(procps_status_t* sp, int flags)
222{
223        struct dirent *entry;
224        char buf[PROCPS_BUFSIZE];
225        char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
226        char *filename_tail;
227        long tasknice;
228        unsigned pid;
229        int n;
230        struct stat sb;
231
232        if (!sp)
233                sp = alloc_procps_scan();
234
235        for (;;) {
236                entry = readdir(sp->dir);
237                if (entry == NULL) {
238                        free_procps_scan(sp);
239                        return NULL;
240                }
241                pid = bb_strtou(entry->d_name, NULL, 10);
242                if (errno)
243                        continue;
244
245                /* After this point we have to break, not continue
246                 * ("continue" would mean that current /proc/NNN
247                 * is not a valid process info) */
248
249                memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
250
251                sp->pid = pid;
252                if (!(flags & ~PSSCAN_PID)) break;
253
254                filename_tail = filename + sprintf(filename, "/proc/%d", pid);
255
256                if (flags & PSSCAN_UIDGID) {
257                        if (stat(filename, &sb))
258                                break;
259                        /* Need comment - is this effective or real UID/GID? */
260                        sp->uid = sb.st_uid;
261                        sp->gid = sb.st_gid;
262                }
263
264                if (flags & PSSCAN_STAT) {
265                        char *cp, *comm1;
266                        int tty;
267                        unsigned long vsz, rss;
268
269                        /* see proc(5) for some details on this */
270                        strcpy(filename_tail, "/stat");
271                        n = read_to_buf(filename, buf);
272                        if (n < 0)
273                                break;
274                        cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
275                        /*if (!cp || cp[1] != ' ')
276                                break;*/
277                        cp[0] = '\0';
278                        if (sizeof(sp->comm) < 16)
279                                BUG_comm_size();
280                        comm1 = strchr(buf, '(');
281                        /*if (comm1)*/
282                                strncpy(sp->comm, comm1 + 1, sizeof(sp->comm));
283
284                        n = sscanf(cp+2,
285                                "%c %u "               /* state, ppid */
286                                "%u %u %d %*s "        /* pgid, sid, tty, tpgid */
287                                "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
288                                "%lu %lu "             /* utime, stime */
289                                "%*s %*s %*s "         /* cutime, cstime, priority */
290                                "%ld "                 /* nice */
291                                "%*s %*s "             /* timeout, it_real_value */
292                                "%lu "                 /* start_time */
293                                "%lu "                 /* vsize */
294                                "%lu "                 /* rss */
295                        /*	"%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
296                        /*	"%u %u %u %u "         signal, blocked, sigignore, sigcatch */
297                        /*	"%lu %lu %lu"          wchan, nswap, cnswap */
298                                ,
299                                sp->state, &sp->ppid,
300                                &sp->pgid, &sp->sid, &tty,
301                                &sp->utime, &sp->stime,
302                                &tasknice,
303                                &sp->start_time,
304                                &vsz,
305                                &rss);
306                        if (n != 11)
307                                break;
308                        /* vsz is in bytes and we want kb */
309                        sp->vsz = vsz >> 10;
310                        /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
311                        sp->rss = rss << sp->shift_pages_to_kb;
312                        sp->tty_major = (tty >> 8) & 0xfff;
313                        sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
314
315                        if (sp->vsz == 0 && sp->state[0] != 'Z')
316                                sp->state[1] = 'W';
317                        else
318                                sp->state[1] = ' ';
319                        if (tasknice < 0)
320                                sp->state[2] = '<';
321                        else if (tasknice) /* > 0 */
322                                sp->state[2] = 'N';
323                        else
324                                sp->state[2] = ' ';
325
326                }
327
328                if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) {
329                        free(sp->argv0);
330                        sp->argv0 = NULL;
331                        strcpy(filename_tail, "/cmdline");
332                        n = read_to_buf(filename, buf);
333                        if (n <= 0)
334                                break;
335                        if (flags & PSSCAN_ARGVN) {
336                                sp->argv_len = n;
337                                sp->argv0 = malloc(n + 1);
338                                memcpy(sp->argv0, buf, n + 1);
339                                /* sp->argv0[n] = '\0'; - buf has it */
340                        } else {
341                                sp->argv_len = 0;
342                                sp->argv0 = strdup(buf);
343                        }
344                }
345                break;
346        }
347        return sp;
348}
349
350pid_t* find_pid_by_name(const char *procName)
351{
352        pid_t* pidList;
353        int i = 0;
354        procps_status_t* p = NULL;
355
356        pidList = xzalloc(sizeof(*pidList));
357        while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN))) {
358                if (comm_match(p, procName)
359                /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
360                 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
361                /* TOOD: we can also try /proc/NUM/exe link, do we want that? */
362                ) {
363                        if (p->state[0] != 'Z')
364                        {
365                                pidList = xrealloc_vector(pidList, 2, i);
366                                pidList[i++] = p->pid;
367                        }
368                }
369        }
370
371        pidList[i] = 0;
372        return pidList;
373}
374
375int pids(char *appname)
376{
377        pid_t *pidList;
378        pid_t *pl;
379        int count = 0;
380
381        pidList = find_pid_by_name(appname);
382        for (pl = pidList; *pl; pl++) {
383                count++;
384        }
385        free(pidList);
386
387        if (count)
388                return 1;
389        else
390                return 0;
391}
392/*end pids()*/
393
394/*??*/
395enum {
396        ACT_IDLE,
397        ACT_TFTP_UPGRADE_UNUSED,
398        ACT_WEB_UPGRADE,
399        ACT_WEBS_UPGRADE_UNUSED,
400        ACT_SW_RESTORE,
401        ACT_HW_RESTORE,
402        ACT_ERASE_NVRAM,
403        ACT_NVRAM_COMMIT,
404        ACT_REBOOT,
405        ACT_UNKNOWN
406};
407/*??*/
408/*check_action*/
409#include <fcntl.h>
410#ifdef DEBUG_NOISY
411#define _dprintf		cprintf
412#define csprintf		cprintf
413#else
414#define _dprintf(args...)	do { } while(0)
415#define csprintf(args...)	do { } while(0)
416#endif
417
418int check_action(void)
419{
420        int a;
421        int r = 3;
422
423        while (f_read("/var/lock/action", &a, sizeof(a)) != sizeof(a)) {
424                sleep(1);
425                if (--r == 0) return ACT_UNKNOWN;
426        }
427        _dprintf("check_action %d\n", a);
428
429        return a;
430}
431/**/
432#endif
433#define DBE 0
434#define LIGHTTPD_PID_FILE_PATH	"/tmp/lighttpd/lighttpd.pid"
435#define LIGHTTPD_MONITOR_PID_FILE_PATH	"/tmp/lighttpd/lighttpd-monitor.pid"
436#define LIGHTTPD_ARPPING_PID_FILE_PATH	"/tmp/lighttpd/lighttpd-arpping.pid"
437
438static siginfo_t last_sigterm_info;
439static siginfo_t last_sighup_info;
440
441static volatile sig_atomic_t start_process    = 1;
442static volatile sig_atomic_t graceful_restart = 0;
443static volatile pid_t pid = -1;
444
445#define BINPATH SBIN_DIR"/lighttpd-monitor"
446#define UNUSED(x) ( (void)(x) )
447
448int is_shutdown = 0;
449
450static void sigaction_handler(int sig, siginfo_t *si, void *context) {
451	static siginfo_t empty_siginfo;
452	UNUSED(context);
453
454	if (!si) si = &empty_siginfo;
455
456	switch (sig) {
457	case SIGTERM:
458		is_shutdown = 1;
459		break;
460	case SIGINT:
461		break;
462	case SIGALRM:
463		break;
464	case SIGHUP:
465		break;
466	case SIGCHLD:
467		break;
468	}
469}
470
471void stop_arpping_process()
472{
473	FILE *fp;
474    char buf[256];
475    pid_t pid = 0;
476    int n;
477
478	if ((fp = fopen(LIGHTTPD_ARPPING_PID_FILE_PATH, "r")) != NULL) {
479		if (fgets(buf, sizeof(buf), fp) != NULL)
480	    	pid = strtoul(buf, NULL, 0);
481		fclose(fp);
482	}
483
484	if (pid > 1 && kill(pid, SIGTERM) == 0) {
485		n = 10;
486		while ((kill(pid, SIGTERM) == 0) && (n-- > 0)) {
487			//Cdbg(DBE,"Mod_smbdav: %s: waiting pid=%d n=%d\n", __FUNCTION__, pid, n);
488			usleep(100 * 1000);
489		}
490	}
491
492	unlink(LIGHTTPD_ARPPING_PID_FILE_PATH);
493}
494
495int main(int argc, char **argv) {
496
497	UNUSED(argc);
498
499	//- Check if same process is running.
500	FILE *fp = fopen(LIGHTTPD_MONITOR_PID_FILE_PATH, "r");
501	if (fp) {
502		fclose(fp);
503		return 0;
504	}
505
506	//- Write PID file
507	pid_t pid = getpid();
508	fp = fopen(LIGHTTPD_MONITOR_PID_FILE_PATH, "w");
509	if (!fp) {
510		exit(EXIT_FAILURE);
511	}
512	fprintf(fp, "%d\n", pid);
513	fclose(fp);
514
515#if EMBEDDED_EANBLE
516	sigset_t sigs_to_catch;
517
518	/* set the signal handler */
519    sigemptyset(&sigs_to_catch);
520    sigaddset(&sigs_to_catch, SIGTERM);
521    sigprocmask(SIG_UNBLOCK, &sigs_to_catch, NULL);
522
523   	signal(SIGTERM, sigaction_handler);
524#else
525	struct sigaction act;
526	memset(&act, 0, sizeof(act));
527	act.sa_handler = SIG_IGN;
528	sigaction(SIGPIPE, &act, NULL);
529	sigaction(SIGUSR1, &act, NULL);
530
531	act.sa_sigaction = sigaction_handler;
532	sigemptyset(&act.sa_mask);
533	act.sa_flags = SA_SIGINFO;
534
535	sigaction(SIGINT,  &act, NULL);
536	sigaction(SIGTERM, &act, NULL);
537	sigaction(SIGHUP,  &act, NULL);
538	sigaction(SIGALRM, &act, NULL);
539	sigaction(SIGCHLD, &act, NULL);
540#endif
541
542	time_t prv_ts = time(NULL);
543
544	int stop_arp_count = 0;
545	int commit_count = 0;
546
547	while (!is_shutdown) {
548
549		sleep(10);
550
551		int start_lighttpd = 0;
552		int start_lighttpd_arp = 0;
553
554		time_t cur_ts = time(NULL);
555
556	#if EMBEDDED_EANBLE
557  		if (!pids("lighttpd")){
558			start_lighttpd = 1;
559  		}
560
561		if (!pids("lighttpd-arpping")){
562			start_lighttpd_arp = 1;
563  		}
564	#else
565		if (!system("pidof lighttpd")){
566			start_lighttpd = 1;
567		}
568
569		if (!system("pidof lighttpd-arpping")){
570			start_lighttpd_arp = 1;
571		}
572	#endif
573
574		//-every 30 sec
575		if(cur_ts - prv_ts >= 30){
576
577			if(start_lighttpd){
578			#if EMBEDDED_EANBLE
579			#ifndef APP_IPKG
580				system("/usr/sbin/lighttpd -f /tmp/lighttpd.conf -D &");
581			#else
582				system("/opt/bin/lighttpd -f /tmp/lighttpd.conf -D &");
583			#endif
584			#else
585				system("./_inst/sbin/lighttpd -f lighttpd.conf &");
586			#endif
587			}
588
589			if(start_lighttpd_arp){
590			#if EMBEDDED_EANBLE
591			#ifndef APP_IPKG
592				system("/usr/sbin/lighttpd-arpping -f br0 &");
593			#else
594				system("/opt/bin/lighttpd-arpping -f br0 &");
595			#endif
596			#else
597				system("./_inst/sbin/lighttpd-arpping -f eth0 &");
598			#endif
599			}
600
601			#if 0
602			//-every 2 hour
603			if(stop_arp_count>=240){
604				stop_arpping_process();
605				stop_arp_count=0;
606			}
607			#endif
608
609			//-every 12 hour
610			if(commit_count>=1440){
611
612				#if EMBEDDED_EANBLE
613				int i, act;
614				for (i = 30; i > 0; --i) {
615			    	if (((act = check_action()) == ACT_IDLE) || (act == ACT_REBOOT)) break;
616			        fprintf(stderr, "Busy with %d. Waiting before shutdown... %d", act, i);
617			        sleep(1);
618			    }
619
620				nvram_do_commit();
621				#endif
622
623				commit_count=0;
624			}
625
626			prv_ts = cur_ts;
627			stop_arp_count++;
628			commit_count++;
629		}
630	}
631
632	//Cdbg(DBE, "Success to terminate lighttpd-monitor.....");
633
634	exit(EXIT_SUCCESS);
635
636	return 0;
637}
638
639