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