slog.c (2290B)
1 /* slog: simple logging daemon */ 2 3 #ifndef _GNU_SOURCE 4 #define _GNU_SOURCE /* needed for PATH_MAX, to, and from */ 5 #endif 6 7 #include "arg.h" 8 #include "util.h" 9 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <limits.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/stat.h> 17 #include <unistd.h> 18 19 static void 20 usage(void) 21 { 22 eprintf("usage: %s [-d dir] [-s bytes] [-n count]\n", argv0); 23 } 24 25 static void 26 mkdir_p(const char *path) 27 { 28 char tmp[PATH_MAX]; 29 char *p; 30 size_t len; 31 32 strlcpy(tmp, path, sizeof(tmp)); 33 len = strlen(tmp); 34 if (len > 0 && tmp[len - 1] == '/') 35 tmp[len - 1] = '\0'; 36 37 for (p = tmp + 1; *p; p++) { 38 if (*p == '/') { 39 *p = '\0'; 40 if (mkdir(tmp, 0755) < 0 && errno != EEXIST) 41 eprintf("mkdir %s:", tmp); 42 *p = '/'; 43 } 44 } 45 if (mkdir(tmp, 0755) < 0 && errno != EEXIST) 46 eprintf("mkdir %s:", tmp); 47 } 48 49 int 50 main(int argc, char *argv[]) 51 { 52 char *dir; 53 char cur[PATH_MAX], from[PATH_MAX], to[PATH_MAX]; 54 long maxsize, maxfiles; 55 int fd, i, n; 56 size_t total; 57 char buf[4096]; 58 59 dir = "."; 60 maxsize = 1048576; 61 maxfiles = 10; 62 63 ARGBEGIN { 64 case 'd': dir = EARGF(usage()); break; 65 case 's': maxsize = estrtonum(EARGF(usage()), 1, LONG_MAX); break; 66 case 'n': maxfiles = estrtonum(EARGF(usage()), 1, 1000); break; 67 default: usage(); 68 } ARGEND 69 70 if (argc) 71 usage(); 72 73 mkdir_p(dir); 74 75 snprintf(cur, sizeof(cur), "%s/current", dir); 76 fd = open(cur, O_WRONLY | O_CREAT | O_APPEND, 0644); 77 if (fd < 0) 78 eprintf("open %s:", cur); 79 80 total = 0; 81 while ((n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { 82 if (writeall(fd, buf, n) < 0) 83 eprintf("write %s:", cur); 84 total += n; 85 if (total < (size_t)maxsize) 86 continue; 87 88 /* rotate: delete oldest, shift others, current -> 0 */ 89 close(fd); 90 snprintf(to, sizeof(to), "%s/%ld", dir, maxfiles - 1); 91 unlink(to); 92 for (i = maxfiles - 2; i >= 0; i--) { 93 snprintf(from, sizeof(from), "%s/%d", dir, i); 94 snprintf(to, sizeof(to), "%s/%d", dir, i + 1); 95 if (rename(from, to) < 0 && errno != ENOENT) 96 weprintf("rename %s -> %s:", from, to); 97 } 98 snprintf(to, sizeof(to), "%s/0", dir); 99 if (rename(cur, to) < 0) 100 weprintf("rename %s -> %s:", cur, to); 101 102 fd = open(cur, O_WRONLY | O_CREAT | O_APPEND, 0644); 103 if (fd < 0) 104 eprintf("open %s:", cur); 105 total = 0; 106 } 107 108 close(fd); 109 return 0; 110 }