1/* vi: set sw=4 ts=4: */ 2/* 3 * circular buffer syslog implementation for busybox 4 * 5 * Copyright (C) 2000 by Gennady Feldman <gfeldman@gena01.com> 6 * 7 * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001 8 * 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 10 */ 11 12#include "libbb.h" 13#include <sys/ipc.h> 14#include <sys/sem.h> 15#include <sys/shm.h> 16 17#define DEBUG 0 18 19enum { KEY_ID = 0x414e4547 }; /* "GENA" */ 20 21static struct shbuf_ds { 22 int32_t size; // size of data - 1 23 int32_t tail; // end of message list 24 char data[1]; // messages 25} *shbuf; 26 27// Semaphore operation structures 28static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup 29static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn 30 31 32static void error_exit(const char *str) ATTRIBUTE_NORETURN; 33static void error_exit(const char *str) 34{ 35 //release all acquired resources 36 shmdt(shbuf); 37 bb_perror_msg_and_die(str); 38} 39 40/* 41 * sem_up - up()'s a semaphore. 42 */ 43static void sem_up(int semid) 44{ 45 if (semop(semid, SMrup, 1) == -1) 46 error_exit("semop[SMrup]"); 47} 48 49static void interrupted(int sig ATTRIBUTE_UNUSED) 50{ 51 signal(SIGINT, SIG_IGN); 52 shmdt(shbuf); 53 exit(0); 54} 55 56int logread_main(int argc, char **argv); 57int logread_main(int argc, char **argv) 58{ 59 int cur; 60 int log_semid; /* ipc semaphore id */ 61 int log_shmid; /* ipc shared memory id */ 62 smallint follow = getopt32(argv, "f"); 63 64 log_shmid = shmget(KEY_ID, 0, 0); 65 if (log_shmid == -1) 66 bb_perror_msg_and_die("can't find syslogd buffer"); 67 68 /* Attach shared memory to our char* */ 69 shbuf = shmat(log_shmid, NULL, SHM_RDONLY); 70 if (shbuf == NULL) 71 bb_perror_msg_and_die("can't access syslogd buffer"); 72 73 log_semid = semget(KEY_ID, 0, 0); 74 if (log_semid == -1) 75 error_exit("can't get access to semaphores for syslogd buffer"); 76 77 signal(SIGINT, interrupted); 78 79 /* Suppose atomic memory read */ 80 /* Max possible value for tail is shbuf->size - 1 */ 81 cur = shbuf->tail; 82 83 /* Loop for logread -f, one pass if there was no -f */ 84 do { 85 unsigned shbuf_size; 86 unsigned shbuf_tail; 87 const char *shbuf_data; 88#if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING 89 int i; 90 int len_first_part; 91 int len_total = len_total; /* for gcc */ 92 char *copy = copy; /* for gcc */ 93#endif 94 if (semop(log_semid, SMrdn, 2) == -1) 95 error_exit("semop[SMrdn]"); 96 97 /* Copy the info, helps gcc to realize that it doesn't change */ 98 shbuf_size = shbuf->size; 99 shbuf_tail = shbuf->tail; 100 shbuf_data = shbuf->data; /* pointer! */ 101 102 if (DEBUG) 103 printf("cur:%d tail:%i size:%i\n", 104 cur, shbuf_tail, shbuf_size); 105 106 if (!follow) { 107 /* advance to oldest complete message */ 108 /* find NUL */ 109 cur += strlen(shbuf_data + cur); 110 if (cur >= shbuf_size) { /* last byte in buffer? */ 111 cur = strnlen(shbuf_data, shbuf_tail); 112 if (cur == shbuf_tail) 113 goto unlock; /* no complete messages */ 114 } 115 /* advance to first byte of the message */ 116 cur++; 117 if (cur >= shbuf_size) /* last byte in buffer? */ 118 cur = 0; 119 } else { /* logread -f */ 120 if (cur == shbuf_tail) { 121 sem_up(log_semid); 122 fflush(stdout); 123 sleep(1); /* TODO: replace me with a sleep_on */ 124 continue; 125 } 126 } 127 128 /* Read from cur to tail */ 129#if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING 130 len_first_part = len_total = shbuf_tail - cur; 131 if (len_total < 0) { 132 /* message wraps: */ 133 /* [SECOND PART.........FIRST PART] */ 134 /* ^data ^tail ^cur ^size */ 135 len_total += shbuf_size; 136 } 137 copy = xmalloc(len_total + 1); 138 if (len_first_part < 0) { 139 /* message wraps (see above) */ 140 len_first_part = shbuf_size - cur; 141 memcpy(copy + len_first_part, shbuf_data, shbuf_tail); 142 } 143 memcpy(copy, shbuf_data + cur, len_first_part); 144 copy[len_total] = '\0'; 145 cur = shbuf_tail; 146#else 147 while (cur != shbuf_tail) { 148 fputs(shbuf_data + cur, stdout); 149 cur += strlen(shbuf_data + cur) + 1; 150 if (cur >= shbuf_size) 151 cur = 0; 152 } 153#endif 154 unlock: 155 /* release the lock on the log chain */ 156 sem_up(log_semid); 157 158#if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING 159 for (i = 0; i < len_total; i += strlen(copy + i) + 1) { 160 fputs(copy + i, stdout); 161 } 162 free(copy); 163#endif 164 } while (follow); 165 166 shmdt(shbuf); 167 168 fflush_stdout_and_exit(EXIT_SUCCESS); 169} 170