svlogd.c (25555B)
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <sys/param.h> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <time.h> 7 #include <poll.h> 8 #include <sys/time.h> 9 #include <unistd.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include "iopause.h" 15 #include "pmatch.h" 16 #include "fmt_ptime.h" 17 #include "alloc.h" 18 #include "stralloc.h" 19 #include "strerr.h" 20 #include "buffer.h" 21 #include "sig.h" 22 #include "env.h" 23 #include "fd.h" 24 #include <sys/wait.h> 25 #include "wait.h" 26 #include "error.h" 27 #include "sgetopt.h" 28 #include "open.h" 29 #include "openreadclose.h" 30 #include "coe.h" 31 #include "lock.h" 32 #include "str.h" 33 #include "byte.h" 34 #include "scan.h" 35 #include "taia.h" 36 #include "fmt.h" 37 #include "ndelay.h" 38 39 #define USAGE " [-ttv] [-r c] [-R abc] [-l len] [-b buflen] dir ..." 40 41 #define FATAL "svlogd: fatal: " 42 #define WARNING "svlogd: warning: " 43 #define PAUSE "svlogd: pausing: " 44 #define INFO "svlogd: info: " 45 46 static const char *progname; 47 48 static unsigned int verbose =0; 49 static unsigned int timestamp =0; 50 static unsigned long linemax =1000; 51 static unsigned long buflen =1024; 52 static unsigned long linelen; 53 54 static const char *replace =""; 55 static char repl =0; 56 57 static const char **fndir; 58 static int fdwdir; 59 static struct stat st; 60 static stralloc sa; 61 static int wstat; 62 static struct taia now; 63 static struct taia trotate; 64 65 static char *databuf; 66 static buffer data; 67 static char *line; 68 static char stamp[FMT_PTIME]; 69 static unsigned int exitasap =0; 70 static unsigned int rotateasap =0; 71 static unsigned int reopenasap =0; 72 static unsigned int linecomplete =1; 73 static unsigned int tmaxflag =0; 74 static int fdudp =-1; 75 static struct pollfd in; 76 77 static struct logdir { 78 int fddir; 79 char *btmp; 80 buffer b; 81 stralloc inst; 82 unsigned long size; 83 unsigned long sizemax; 84 unsigned long nmax; 85 unsigned long nmin; 86 unsigned long tmax; 87 struct taia trotate; 88 stralloc processor; 89 int ppid; 90 char fnsave[FMT_PTIME]; 91 char *name; 92 int fdcur; 93 int fdlock; 94 char match; 95 char matcherr; 96 struct sockaddr_in udpaddr; 97 unsigned int udponly; 98 stralloc prefix; 99 } *dir; 100 static unsigned int dirn =0; 101 102 static void usage() { strerr_die4x(111, "usage: ", progname, USAGE, "\n"); } 103 static void die_nomem() { strerr_die2x(111, FATAL, "out of memory."); } 104 static void fatal(char *m0) { strerr_die3sys(111, FATAL, m0, ": "); } 105 static void fatalx(char *m0) { strerr_die2x(111, FATAL, m0); } 106 static void fatal2(char *m0, char *m1) 107 { 108 strerr_die5sys(111, FATAL, m0, ": ", m1, ": "); 109 } 110 static void warn(char *m0) { strerr_warn3(WARNING, m0, ": ", &strerr_sys); } 111 static void warn2(char *m0, char *m1) 112 { 113 strerr_warn5(WARNING, m0, ": ", m1, ": ", &strerr_sys); 114 } 115 static void warnx(char *m0, char *m1) { strerr_warn4(WARNING, m0, ": ", m1, 0); } 116 static void pause_nomem() { strerr_warn2(PAUSE, "out of memory.", 0); sleep(3); } 117 static void pause1(char *m0) { strerr_warn3(PAUSE, m0, ": ", &strerr_sys); sleep(3); } 118 static void pause2(char *m0, char *m1) 119 { 120 strerr_warn5(PAUSE, m0, ": ", m1, ": ", &strerr_sys); 121 sleep(3); 122 } 123 124 static unsigned int processorstart(struct logdir *ld) 125 { 126 int pid; 127 128 if (! ld->processor.len) return(0); 129 if (ld->ppid) { 130 warnx("processor already running", ld->name); 131 return(0); 132 } 133 while ((pid =fork()) == -1) 134 pause2("unable to fork for processor", ld->name); 135 if (! pid) { 136 char *prog[4]; 137 int fd; 138 139 /* child */ 140 sig_uncatch(sig_term); 141 sig_uncatch(sig_alarm); 142 sig_uncatch(sig_hangup); 143 sig_unblock(sig_term); 144 sig_unblock(sig_alarm); 145 sig_unblock(sig_hangup); 146 147 if (verbose) 148 strerr_warn5(INFO, "processing: ", ld->name, "/", ld->fnsave, 0); 149 if ((fd =open_read(ld->fnsave)) == -1) 150 fatal2("unable to open input for processor", ld->name); 151 if (fd_move(0, fd) == -1) 152 fatal2("unable to move filedescriptor for processor", ld->name); 153 ld->fnsave[26] ='t'; 154 if ((fd =open_trunc(ld->fnsave)) == -1) 155 fatal2("unable to open output for processor", ld->name); 156 if (fd_move(1, fd) == -1) 157 fatal2("unable to move filedescriptor for processor", ld->name); 158 if ((fd =open_read("state")) == -1) { 159 if (errno == error_noent) { 160 if ((fd =open_trunc("state")) == -1) 161 fatal2("unable to create empty state for processor", ld->name); 162 close(fd); 163 if ((fd =open_read("state")) == -1) 164 fatal2("unable to open state for processor", ld->name); 165 } 166 else 167 fatal2("unable to open state for processor", ld->name); 168 } 169 if (fd_move(4, fd) == -1) 170 fatal2("unable to move filedescriptor for processor", ld->name); 171 if ((fd =open_trunc("newstate")) == -1) 172 fatal2("unable to open newstate for processor", ld->name); 173 if (fd_move(5, fd) == -1) 174 fatal2("unable to move filedescriptor for processor", ld->name); 175 176 prog[0] = "sh"; 177 prog[1] = "-c"; 178 prog[2] = ld->processor.s; 179 prog[3] = 0; 180 execve("/bin/sh", prog, environ); 181 fatal2("unable to run processor", ld->name); 182 } 183 ld->ppid =pid; 184 return(1); 185 } 186 static unsigned int processorstop(struct logdir *ld) 187 { 188 char f[28]; 189 190 if (ld->ppid) { 191 sig_unblock(sig_hangup); 192 while (wait_pid(&wstat, ld->ppid) == -1) 193 pause2("error waiting for processor", ld->name); 194 sig_block(sig_hangup); 195 ld->ppid =0; 196 } 197 if (ld->fddir == -1) return(1); 198 while (fchdir(ld->fddir) == -1) 199 pause2("unable to change directory, want processor", ld->name); 200 if (wait_exitcode(wstat) != 0) { 201 warnx("processor failed, restart", ld->name); 202 ld->fnsave[26] ='t'; 203 unlink(ld->fnsave); 204 ld->fnsave[26] ='u'; 205 processorstart(ld); 206 while (fchdir(fdwdir) == -1) 207 pause1("unable to change to initial working directory"); 208 return(ld->processor.len ? 0 : 1); 209 } 210 ld->fnsave[26] ='t'; 211 byte_copy(f, 26, ld->fnsave); 212 f[26] ='s'; f[27] =0; 213 while (rename(ld->fnsave, f) == -1) 214 pause2("unable to rename processed", ld->name); 215 while (chmod(f, 0744) == -1) 216 pause2("unable to set mode of processed", ld->name); 217 ld->fnsave[26] ='u'; 218 if (unlink(ld->fnsave) == -1) 219 strerr_warn5(WARNING, "unable to unlink: ", ld->name, "/", ld->fnsave, 0); 220 while (rename("newstate", "state") == -1) 221 pause2("unable to rename state", ld->name); 222 if (verbose) strerr_warn5(INFO, "processed: ", ld->name, "/", f, 0); 223 while (fchdir(fdwdir) == -1) 224 pause1("unable to change to initial working directory"); 225 return(1); 226 } 227 228 static void rmoldest(struct logdir *ld) 229 { 230 DIR *d; 231 struct dirent *f; 232 char oldest[FMT_PTIME]; 233 int n =0; 234 235 oldest[0] ='A'; oldest[1] =oldest[27] =0; 236 while (! (d =opendir("."))) 237 pause2("unable to open directory, want rotate", ld->name); 238 errno =0; 239 while ((f =readdir(d))) 240 if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) { 241 if (f->d_name[26] == 't') { 242 if (unlink(f->d_name) == -1) 243 warn2("unable to unlink processor leftover", f->d_name); 244 } 245 else { 246 ++n; 247 if (str_diff(f->d_name, oldest) < 0) byte_copy(oldest, 27, f->d_name); 248 } 249 errno =0; 250 } 251 if (errno) warn2("unable to read directory", ld->name); 252 closedir(d); 253 254 if (ld->nmax && (n > ld->nmax)) { 255 if (verbose) strerr_warn5(INFO, "delete: ", ld->name, "/", oldest, 0); 256 if ((*oldest == '@') && (unlink(oldest) == -1)) 257 warn2("unable to unlink oldest logfile", ld->name); 258 } 259 } 260 261 static unsigned int rotate(struct logdir *ld) 262 { 263 char tmp[FMT_ULONG +1]; 264 265 if (ld->fddir == -1) { ld->tmax =0; return(0); } 266 if (ld->ppid) while(! processorstop(ld)); 267 268 while (fchdir(ld->fddir) == -1) 269 pause2("unable to change directory, want rotate", ld->name); 270 271 /* create new filename */ 272 ld->fnsave[25] ='.'; 273 if (ld->processor.len) 274 ld->fnsave[26] ='u'; 275 else 276 ld->fnsave[26] ='s'; 277 ld->fnsave[27] =0; 278 do { 279 taia_now(&now); 280 fmt_taia(ld->fnsave, &now); 281 errno =0; 282 } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent)); 283 284 if (ld->tmax && taia_less(&ld->trotate, &now)) { 285 taia_uint(&ld->trotate, ld->tmax); 286 taia_add(&ld->trotate, &now, &ld->trotate); 287 if (taia_less(&ld->trotate, &trotate)) trotate =ld->trotate; 288 } 289 290 if (ld->size > 0) { 291 buffer_flush(&ld->b); 292 while (fsync(ld->fdcur) == -1) 293 pause2("unable to fsync current logfile", ld->name); 294 while (fchmod(ld->fdcur, 0744) == -1) 295 pause2("unable to set mode of current", ld->name); 296 close(ld->fdcur); 297 if (verbose) { 298 tmp[0] =' '; tmp[fmt_ulong(tmp +1, ld->size) +1] =0; 299 strerr_warn6(INFO, "rename: ", ld->name, "/current ", 300 ld->fnsave, tmp, 0); 301 } 302 while (rename("current", ld->fnsave) == -1) 303 pause2("unable to rename current", ld->name); 304 while ((ld->fdcur =open_append("current")) == -1) 305 pause2("unable to create new current", ld->name); 306 coe(ld->fdcur); 307 ld->size =0; 308 while (fchmod(ld->fdcur, 0644) == -1) 309 pause2("unable to set mode of current", ld->name); 310 rmoldest(ld); 311 processorstart(ld); 312 } 313 314 while (fchdir(fdwdir) == -1) 315 pause1("unable to change to initial working directory"); 316 return(1); 317 } 318 319 static int buffer_pwrite(int n, char const *s, unsigned int len) 320 { 321 int i; 322 323 if ((dir +n)->sizemax) { 324 if ((dir +n)->size >= (dir +n)->sizemax) rotate(dir +n); 325 if (len > ((dir +n)->sizemax -(dir +n)->size)) 326 len =(dir +n)->sizemax -(dir +n)->size; 327 } 328 while ((i =write((dir +n)->fdcur, s, len)) == -1) { 329 if ((errno == ENOSPC) && ((dir +n)->nmin < (dir +n)->nmax)) { 330 DIR *d; 331 struct dirent *f; 332 char oldest[FMT_PTIME]; 333 int j =0; 334 335 while (fchdir((dir +n)->fddir) == -1) 336 pause2("unable to change directory, want remove old logfile", 337 (dir +n)->name); 338 oldest[0] ='A'; oldest[1] =oldest[27] =0; 339 while (! (d =opendir("."))) 340 pause2("unable to open directory, want remove old logfile", 341 (dir +n)->name); 342 errno =0; 343 while ((f =readdir(d))) 344 if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) { 345 ++j; 346 if (str_diff(f->d_name, oldest) < 0) 347 byte_copy(oldest, 27, f->d_name); 348 } 349 if (errno) warn2("unable to read directory, want remove old logfile", 350 (dir +n)->name); 351 closedir(d); 352 errno =ENOSPC; 353 if (j > (dir +n)->nmin) 354 if (*oldest == '@') { 355 strerr_warn5(WARNING, "out of disk space, delete: ", (dir +n)->name, 356 "/", oldest, 0); 357 errno =0; 358 if (unlink(oldest) == -1) { 359 warn2("unable to unlink oldest logfile", (dir +n)->name); 360 errno =ENOSPC; 361 } 362 while (fchdir(fdwdir) == -1) 363 pause1("unable to change to initial working directory"); 364 } 365 } 366 if (errno) pause2("unable to write to current", (dir +n)->name); 367 } 368 369 (dir +n)->size +=i; 370 if ((dir +n)->sizemax) 371 if (s[i -1] == '\n') 372 if ((dir +n)->size >= ((dir +n)->sizemax -linemax)) rotate(dir +n); 373 return(i); 374 } 375 376 static void logdir_close(struct logdir *ld) 377 { 378 if (ld->fddir == -1) return; 379 if (verbose) strerr_warn3(INFO, "close: ", ld->name, 0); 380 close(ld->fddir); 381 ld->fddir =-1; 382 if (ld->fdcur == -1) return; /* impossible */ 383 buffer_flush(&ld->b); 384 while (fsync(ld->fdcur) == -1) 385 pause2("unable to fsync current logfile", ld->name); 386 while (fchmod(ld->fdcur, 0744) == -1) 387 pause2("unable to set mode of current", ld->name); 388 close(ld->fdcur); 389 ld->fdcur =-1; 390 if (ld->fdlock == -1) return; /* impossible */ 391 close(ld->fdlock); 392 ld->fdlock =-1; 393 while (! stralloc_copys(&ld->processor, "")) pause_nomem(); 394 } 395 396 /* taken from libdjbdns */ 397 static unsigned int ip4_scan(const char *s,char ip[4]) 398 { 399 unsigned int i; 400 unsigned int len; 401 unsigned long u; 402 403 len = 0; 404 i = scan_ulong(s,&u); if (!i) return 0; ip[0] = u; s += i; len += i; 405 if (*s != '.') return 0; ++s; ++len; 406 i = scan_ulong(s,&u); if (!i) return 0; ip[1] = u; s += i; len += i; 407 if (*s != '.') return 0; ++s; ++len; 408 i = scan_ulong(s,&u); if (!i) return 0; ip[2] = u; s += i; len += i; 409 if (*s != '.') return 0; ++s; ++len; 410 i = scan_ulong(s,&u); if (!i) return 0; ip[3] = u; s += i; len += i; 411 return len; 412 } 413 414 static unsigned int logdir_open(struct logdir *ld, const char *fn) 415 { 416 int i; 417 418 if ((ld->fddir =open_read(fn)) == -1) { 419 warn2("unable to open log directory", (char const*)fn); 420 return(0); 421 } 422 coe(ld->fddir); 423 if (fchdir(ld->fddir) == -1) { 424 logdir_close(ld); 425 warn2("unable to change directory", (char const*)fn); 426 return(0); 427 } 428 ld->fdlock =open_append("lock"); 429 if ((ld->fdlock == -1) || (lock_exnb(ld->fdlock) == -1)) { 430 logdir_close(ld); 431 warn2("unable to lock directory", (char const*)fn); 432 while (fchdir(fdwdir) == -1) 433 pause1("unable to change to initial working directory"); 434 return(0); 435 } 436 coe(ld->fdlock); 437 438 ld->size =0; 439 ld->sizemax =1000000; 440 ld->nmax =ld->nmin =10; 441 ld->tmax =0; 442 ld->name =(char const*)fn; 443 ld->ppid =0; 444 ld->match ='+'; 445 ld->udpaddr.sin_family =AF_INET; 446 ld->udpaddr.sin_port =0; 447 ld->udponly =0; 448 while (! stralloc_copys(&ld->prefix, "")) pause_nomem(); 449 while (! stralloc_copys(&ld->inst, "")) pause_nomem(); 450 while (! stralloc_copys(&ld->processor, "")) pause_nomem(); 451 452 /* read config */ 453 if ((i =openreadclose("config", &sa, 128)) == -1) 454 warn2("unable to read config", ld->name); 455 if (i != 0) { 456 int len, c; 457 unsigned long port; 458 459 if (verbose) strerr_warn4(INFO, "read: ", ld->name, "/config", 0); 460 for (i =0; i +1 < sa.len; ++i) { 461 len =byte_chr(&sa.s[i], sa.len -i, '\n'); 462 sa.s[len +i] =0; 463 switch(sa.s[i]) { 464 case '\n': 465 case '#': 466 break; 467 case '+': 468 case '-': 469 case 'e': 470 case 'E': 471 while (! stralloc_catb(&ld->inst, &sa.s[i], len)) pause_nomem(); 472 while (! stralloc_0(&ld->inst)) pause_nomem(); 473 break; 474 case 's': 475 switch (sa.s[scan_ulong(&sa.s[i +1], &ld->sizemax) +i +1]) { 476 case 'm': 477 ld->sizemax *=1024; 478 __attribute__((fallthrough)); 479 case 'k': ld->sizemax *=1024; 480 } 481 break; 482 case 'n': 483 scan_ulong(&sa.s[i +1], &ld->nmax); 484 break; 485 case 'N': 486 scan_ulong(&sa.s[i +1], &ld->nmin); 487 break; 488 case 't': 489 switch (sa.s[scan_ulong(&sa.s[i +1], &ld->tmax) +i +1]) { 490 /* case 'd': ld->tmax *=24; */ 491 case 'h': 492 ld->tmax *=60; 493 __attribute__((fallthrough)); 494 case 'm': ld->tmax *=60; 495 } 496 if (ld->tmax) { 497 taia_uint(&ld->trotate, ld->tmax); 498 taia_add(&ld->trotate, &now, &ld->trotate); 499 if (! tmaxflag || taia_less(&ld->trotate, &trotate)) 500 trotate =ld->trotate; 501 tmaxflag =1; 502 } 503 break; 504 case '!': 505 if (len > 1) { 506 while (! stralloc_copys(&ld->processor, &sa.s[i +1])) pause_nomem(); 507 while (! stralloc_0(&ld->processor)) pause_nomem(); 508 } 509 break; 510 case 'U': 511 ld->udponly =1; 512 __attribute__((fallthrough)); 513 case 'u': 514 if (! (c =ip4_scan(sa.s +i +1, (char *)&ld->udpaddr.sin_addr))) { 515 warnx("unable to scan ip address", sa.s +i +1); 516 break; 517 } 518 if (sa.s[i +1 +c] == ':') { 519 scan_ulong(sa.s +i +c +2, &port); 520 if (port == 0) { 521 warnx("unable to scan port number", sa.s +i +c +2); 522 break; 523 } 524 } 525 else 526 port =514; 527 ld->udpaddr.sin_port =htons(port); 528 break; 529 case 'p': 530 if (len > 1) { 531 while (! stralloc_copys(&ld->prefix, &sa.s[i +1])) pause_nomem(); 532 while (! stralloc_0(&ld->prefix)) pause_nomem(); 533 } 534 break; 535 } 536 i +=len; 537 } 538 } 539 540 /* open current */ 541 if ((i =stat("current", &st)) != -1) { 542 if (st.st_size && ! (st.st_mode & S_IXUSR)) { 543 ld->fnsave[25] ='.'; ld->fnsave[26] ='u'; ld->fnsave[27] =0; 544 do { 545 taia_now(&now); 546 fmt_taia(ld->fnsave, &now); 547 errno =0; 548 } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent)); 549 while (rename("current", ld->fnsave) == -1) 550 pause2("unable to rename current", ld->name); 551 rmoldest(ld); 552 i =-1; 553 } 554 else 555 ld->size =st.st_size; 556 } 557 else 558 if (errno != error_noent) { 559 logdir_close(ld); 560 warn2("unable to stat current", ld->name); 561 while (fchdir(fdwdir) == -1) 562 pause1("unable to change to initial working directory"); 563 return(0); 564 } 565 while ((ld->fdcur =open_append("current")) == -1) 566 pause2("unable to open current", ld->name); 567 coe(ld->fdcur); 568 while (fchmod(ld->fdcur, 0644) == -1) 569 pause2("unable to set mode of current", ld->name); 570 buffer_init(&ld->b, buffer_pwrite, ld -dir, ld->btmp, buflen); 571 572 if (verbose) { 573 if (i == 0) strerr_warn4(INFO, "append: ", ld->name, "/current", 0); 574 else strerr_warn4(INFO, "new: ", ld->name, "/current", 0); 575 } 576 577 while (fchdir(fdwdir) == -1) 578 pause1("unable to change to initial working directory"); 579 return(1); 580 } 581 582 static void logdirs_reopen(void) 583 { 584 int l; 585 int ok =0; 586 587 tmaxflag =0; 588 taia_now(&now); 589 for (l =0; l < dirn; ++l) { 590 logdir_close(&dir[l]); 591 if (logdir_open(&dir[l], fndir[l])) ok =1; 592 } 593 if (! ok) fatalx("no functional log directories."); 594 } 595 596 static int buffer_pread(int fd, char const*s, unsigned int len) 597 { 598 int i; 599 600 for (i =0; i < dirn; ++i) buffer_flush(&dir[i].b); 601 if (rotateasap) { 602 for (i =0; i < dirn; ++i) rotate(dir +i); 603 rotateasap =0; 604 } 605 if (exitasap) { 606 if (linecomplete) return(0); 607 len =1; 608 } 609 if (reopenasap) { 610 logdirs_reopen(); 611 reopenasap =0; 612 } 613 taia_now(&now); 614 taia_uint(&trotate, 2744); 615 taia_add(&trotate, &now, &trotate); 616 for (i =0; i < dirn; ++i) 617 if ((dir +i)->tmax) { 618 if (taia_less(&dir[i].trotate, &now)) rotate(dir +i); 619 if (taia_less(&dir[i].trotate, &trotate)) trotate =dir[i].trotate; 620 } 621 sig_unblock(sig_term); 622 sig_unblock(sig_child); 623 sig_unblock(sig_alarm); 624 sig_unblock(sig_hangup); 625 iopause(&in, 1, &trotate, &now); 626 sig_block(sig_term); 627 sig_block(sig_child); 628 sig_block(sig_alarm); 629 sig_block(sig_hangup); 630 i =read(fd, s, len); 631 if (i == -1) { 632 if (errno == error_again) errno =error_intr; 633 if (errno != error_intr) warn("unable to read standard input"); 634 } 635 if (i > 0) linecomplete =(s[i -1] == '\n'); 636 return(i); 637 } 638 static void sig_term_handler( int s ) 639 { 640 if (verbose) strerr_warn2(INFO, "sigterm received.", 0); 641 exitasap =1; 642 } 643 static void sig_child_handler( int s ) 644 { 645 int pid, l; 646 647 if (verbose) strerr_warn2(INFO, "sigchild received.", 0); 648 while ((pid =waitpid( -1, &wstat, WNOHANG )) > 0) 649 for (l =0; l < dirn; ++l) 650 if (dir[l].ppid == pid) { 651 dir[l].ppid =0; 652 processorstop(&dir[l]); 653 break; 654 } 655 } 656 static void sig_alarm_handler( int s ) 657 { 658 if (verbose) strerr_warn2(INFO, "sigalarm received.", 0); 659 rotateasap =1; 660 } 661 static void sig_hangup_handler( int s ) 662 { 663 if (verbose) strerr_warn2(INFO, "sighangup received.", 0); 664 reopenasap =1; 665 } 666 667 static void logmatch(struct logdir *ld) 668 { 669 int i; 670 671 ld->match ='+'; 672 ld->matcherr ='E'; 673 for (i =0; i < ld->inst.len; ++i) { 674 switch(ld->inst.s[i]) { 675 case '+': 676 case '-': 677 if (pmatch(&ld->inst.s[i +1], line, linelen)) 678 ld->match =ld->inst.s[i]; 679 break; 680 case 'e': 681 case 'E': 682 if (pmatch(&ld->inst.s[i +1], line, linelen)) 683 ld->matcherr =ld->inst.s[i]; 684 break; 685 } 686 i +=byte_chr(&ld->inst.s[i], ld->inst.len -i, 0); 687 } 688 } 689 690 #define buffer_PUTC(s,c) \ 691 ( ((s)->n != (s)->p) \ 692 ? ( (s)->x[(s)->p++] = (c), 0 ) \ 693 : buffer_put((s),&(c),1) \ 694 ) 695 696 #define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) 697 698 #define buffer_GETC(s,c) \ 699 ( ((s)->p > 0) \ 700 ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \ 701 : buffer_get((s),(c),1) \ 702 ) 703 704 int main(int argc, const char **argv) 705 { 706 int i; 707 int opt; 708 709 progname =*argv; 710 711 while ((opt =getopt(argc, argv, "R:r:l:b:tvV")) != opteof) { 712 switch(opt) { 713 case 'R': 714 replace =optarg; 715 if (! repl) repl ='_'; 716 break; 717 case 'r': 718 repl =*optarg; 719 if (! repl || *(optarg +1)) usage(); 720 break; 721 case 'l': 722 scan_ulong(optarg, &linemax); 723 if (linemax == 0) linemax =1000; 724 break; 725 case 'b': 726 scan_ulong(optarg, &buflen); 727 if (buflen == 0) buflen =1024; 728 break; 729 case 't': 730 if (++timestamp > 3) timestamp =3; 731 break; 732 case 'v': 733 ++verbose; 734 break; 735 case 'V': 736 strerr_warn1(VERSION, 0); 737 __attribute__((fallthrough)); 738 case '?': usage(); 739 } 740 } 741 argv +=optind; 742 743 dirn =argc -optind; 744 if (dirn <= 0) usage(); 745 if (buflen <= linemax) usage(); 746 if ((fdwdir =open_read(".")) == -1) 747 fatal("unable to open current working directory"); 748 coe(fdwdir); 749 dir =(struct logdir*)alloc(dirn *sizeof(struct logdir)); 750 if (! dir) die_nomem(); 751 memset(dir, 0, dirn * sizeof(struct logdir)); 752 for (i =0; i < dirn; ++i) { 753 dir[i].fddir =-1; dir[i].fdcur =-1; 754 dir[i].btmp =(char*)alloc(buflen *sizeof(char)); 755 if (! dir[i].btmp) die_nomem(); 756 dir[i].ppid =0; 757 } 758 databuf =(char*)alloc(buflen *sizeof(char)); 759 if (! databuf) die_nomem(); 760 buffer_init(&data, buffer_pread, 0, databuf, buflen); 761 line =(char*)alloc(linemax *sizeof(char)); 762 if (! line) die_nomem(); 763 fndir =argv; 764 in.fd =0; 765 in.events = POLLIN; 766 ndelay_on(in.fd); 767 768 sig_block(sig_term); 769 sig_block(sig_child); 770 sig_block(sig_alarm); 771 sig_block(sig_hangup); 772 sig_catch(sig_term, sig_term_handler); 773 sig_catch(sig_child, sig_child_handler); 774 sig_catch(sig_alarm, sig_alarm_handler); 775 sig_catch(sig_hangup, sig_hangup_handler); 776 777 logdirs_reopen(); 778 779 for(;;) { 780 char ch; 781 782 linelen =0; 783 for (linelen =0; linelen < linemax; ++linelen) { 784 if (buffer_GETC(&data, &ch) <= 0) { 785 exitasap =1; 786 break; 787 } 788 if (! linelen && timestamp) { 789 taia_now(&now); 790 switch (timestamp) { 791 case 1: fmt_taia(stamp, &now); break; 792 case 2: fmt_ptime(stamp, &now); break; 793 case 3: fmt_ptime_iso8601(stamp, &now); break; 794 } 795 stamp[25] =' '; stamp[26] =0; 796 } 797 if (ch == '\n') break; 798 if (repl) { 799 if ((ch < 32) || (ch > 126)) 800 ch =repl; 801 else 802 for (i =0; replace[i]; ++i) 803 if (ch == replace[i]) { 804 ch =repl; 805 break; 806 } 807 } 808 line[linelen] =ch; 809 } 810 if (exitasap && ! data.p) break; /* data buffer is empty */ 811 for (i =0; i < dirn; ++i) 812 if (dir[i].fddir != -1) { 813 if (dir[i].inst.len) logmatch(&dir[i]); 814 if (dir[i].matcherr == 'e') { 815 if (timestamp) buffer_puts(buffer_2, stamp); 816 if (dir[i].prefix.len) buffer_puts(buffer_2, dir[i].prefix.s); 817 buffer_put(buffer_2, line, linelen); 818 if (linelen == linemax) buffer_puts(buffer_2, "..."); 819 buffer_put(buffer_2, "\n", 1); buffer_flush(buffer_2); 820 } 821 if (dir[i].match != '+') continue; 822 if (dir[i].udpaddr.sin_port != 0) { 823 fdudp =socket(AF_INET, SOCK_DGRAM, 0); 824 if (fdudp) 825 if (ndelay_on(fdudp) == -1) { 826 close(fdudp); 827 fdudp =-1; 828 } 829 if (fdudp == -1) { 830 buffer_puts(&dir[i].b, "warning: no udp socket available: "); 831 if (timestamp) buffer_puts(&dir[i].b, stamp); 832 if (dir[i].prefix.len) buffer_puts(&dir[i].b, dir[i].prefix.s); 833 buffer_put(&dir[i].b, line, linelen); 834 buffer_put(&dir[i].b, "\n", 1); 835 buffer_flush(&dir[i].b); 836 } 837 else { 838 while (! stralloc_copys(&sa, "")) pause_nomem(); 839 if (timestamp) 840 while (! stralloc_cats(&sa, stamp)) pause_nomem(); 841 if (dir[i].prefix.len) 842 while (! stralloc_cats(&sa, dir[i].prefix.s)) pause_nomem(); 843 while (! stralloc_catb(&sa, line, linelen)) pause_nomem(); 844 if (linelen == linemax) 845 while (! stralloc_cats(&sa, "...")) pause_nomem(); 846 while (! stralloc_append(&sa, "\n")) pause_nomem(); 847 if (sendto(fdudp, sa.s, sa.len, 0, 848 (struct sockaddr *)&dir[i].udpaddr, 849 sizeof(dir[i].udpaddr)) != sa.len) { 850 buffer_puts(&dir[i].b, "warning: failure sending through udp: "); 851 buffer_put(&dir[i].b, sa.s, sa.len); 852 buffer_flush(&dir[i].b); 853 } 854 close(fdudp); 855 } 856 } 857 if (! dir[i].udponly) { 858 if (timestamp) buffer_puts(&dir[i].b, stamp); 859 if (dir[i].prefix.len) buffer_puts(&dir[i].b, dir[i].prefix.s); 860 buffer_put(&dir[i].b, line, linelen); 861 } 862 } 863 if (linelen == linemax) 864 for (;;) { 865 if (buffer_GETC(&data, &ch) <= 0) { 866 exitasap =1; 867 break; 868 } 869 if (ch == '\n') break; 870 for (i =0; i < dirn; ++i) 871 if (dir[i].fddir != -1) { 872 if (dir[i].match != '+') continue; 873 if (! dir[i].udponly) buffer_PUTC(&dir[i].b, ch); 874 } 875 } 876 for (i =0; i < dirn; ++i) 877 if (dir[i].fddir != -1) { 878 if (dir[i].match != '+') continue; 879 if (! dir[i].udponly) { 880 ch ='\n'; 881 buffer_PUTC(&dir[i].b, ch); 882 buffer_flush(&dir[i].b); 883 } 884 } 885 } 886 887 for (i =0; i < dirn; ++i) { 888 if (dir[i].ppid) while (! processorstop(&dir[i])); 889 logdir_close(&dir[i]); 890 } 891 _exit(0); 892 }