logread.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 source tree.
  10. */
  11. //usage:#define logread_trivial_usage
  12. //usage: "[-fF]"
  13. //usage:#define logread_full_usage "\n\n"
  14. //usage: "Show messages in syslogd's circular buffer\n"
  15. //usage: "\n -f Output data as log grows"
  16. //usage: "\n -F Same as -f, but dump buffer first"
  17. #include "libbb.h"
  18. #include <sys/ipc.h>
  19. #include <sys/sem.h>
  20. #include <sys/shm.h>
  21. #define DEBUG 0
  22. /* our shared key (syslogd.c and logread.c must be in sync) */
  23. enum { KEY_ID = 0x414e4547 }; /* "GENA" */
  24. struct shbuf_ds {
  25. int32_t size; // size of data - 1
  26. int32_t tail; // end of message list
  27. char data[1]; // messages
  28. };
  29. static const struct sembuf init_sem[3] = {
  30. {0, -1, IPC_NOWAIT | SEM_UNDO},
  31. {1, 0}, {0, +1, SEM_UNDO}
  32. };
  33. struct globals {
  34. struct sembuf SMrup[1]; // {0, -1, IPC_NOWAIT | SEM_UNDO},
  35. struct sembuf SMrdn[2]; // {1, 0}, {0, +1, SEM_UNDO}
  36. struct shbuf_ds *shbuf;
  37. } FIX_ALIASING;
  38. #define G (*(struct globals*)&bb_common_bufsiz1)
  39. #define SMrup (G.SMrup)
  40. #define SMrdn (G.SMrdn)
  41. #define shbuf (G.shbuf)
  42. #define INIT_G() do { \
  43. memcpy(SMrup, init_sem, sizeof(init_sem)); \
  44. } while (0)
  45. #if 0
  46. static void error_exit(const char *str) NORETURN;
  47. static void error_exit(const char *str)
  48. {
  49. /* Release all acquired resources */
  50. shmdt(shbuf);
  51. bb_perror_msg_and_die(str);
  52. }
  53. #else
  54. /* On Linux, shmdt is not mandatory on exit */
  55. # define error_exit(str) bb_perror_msg_and_die(str)
  56. #endif
  57. /*
  58. * sem_up - up()'s a semaphore.
  59. */
  60. static void sem_up(int semid)
  61. {
  62. if (semop(semid, SMrup, 1) == -1)
  63. error_exit("semop[SMrup]");
  64. }
  65. static void interrupted(int sig)
  66. {
  67. /* shmdt(shbuf); - on Linux, shmdt is not mandatory on exit */
  68. kill_myself_with_sig(sig);
  69. }
  70. int logread_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  71. int logread_main(int argc UNUSED_PARAM, char **argv)
  72. {
  73. unsigned cur;
  74. int log_semid; /* ipc semaphore id */
  75. int log_shmid; /* ipc shared memory id */
  76. int follow = getopt32(argv, "fF");
  77. INIT_G();
  78. log_shmid = shmget(KEY_ID, 0, 0);
  79. if (log_shmid == -1)
  80. bb_perror_msg_and_die("can't %s syslogd buffer", "find");
  81. /* Attach shared memory to our char* */
  82. shbuf = shmat(log_shmid, NULL, SHM_RDONLY);
  83. if (shbuf == NULL)
  84. bb_perror_msg_and_die("can't %s syslogd buffer", "access");
  85. log_semid = semget(KEY_ID, 0, 0);
  86. if (log_semid == -1)
  87. error_exit("can't get access to semaphores for syslogd buffer");
  88. bb_signals(BB_FATAL_SIGS, interrupted);
  89. /* Suppose atomic memory read */
  90. /* Max possible value for tail is shbuf->size - 1 */
  91. cur = shbuf->tail;
  92. /* Loop for -f or -F, one pass otherwise */
  93. do {
  94. unsigned shbuf_size;
  95. unsigned shbuf_tail;
  96. const char *shbuf_data;
  97. #if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING
  98. int i;
  99. int len_first_part;
  100. int len_total = len_total; /* for gcc */
  101. char *copy = copy; /* for gcc */
  102. #endif
  103. if (semop(log_semid, SMrdn, 2) == -1)
  104. error_exit("semop[SMrdn]");
  105. /* Copy the info, helps gcc to realize that it doesn't change */
  106. shbuf_size = shbuf->size;
  107. shbuf_tail = shbuf->tail;
  108. shbuf_data = shbuf->data; /* pointer! */
  109. if (DEBUG)
  110. printf("cur:%u tail:%u size:%u\n",
  111. cur, shbuf_tail, shbuf_size);
  112. if (!(follow & 1)) { /* not -f */
  113. /* if -F, "convert" it to -f, so that we dont
  114. * dump the entire buffer on each iteration
  115. */
  116. follow >>= 1;
  117. /* advance to oldest complete message */
  118. /* find NUL */
  119. cur += strlen(shbuf_data + cur);
  120. if (cur >= shbuf_size) { /* last byte in buffer? */
  121. cur = strnlen(shbuf_data, shbuf_tail);
  122. if (cur == shbuf_tail)
  123. goto unlock; /* no complete messages */
  124. }
  125. /* advance to first byte of the message */
  126. cur++;
  127. if (cur >= shbuf_size) /* last byte in buffer? */
  128. cur = 0;
  129. } else { /* -f */
  130. if (cur == shbuf_tail) {
  131. sem_up(log_semid);
  132. fflush_all();
  133. sleep(1); /* TODO: replace me with a sleep_on */
  134. continue;
  135. }
  136. }
  137. /* Read from cur to tail */
  138. #if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING
  139. len_first_part = len_total = shbuf_tail - cur;
  140. if (len_total < 0) {
  141. /* message wraps: */
  142. /* [SECOND PART.........FIRST PART] */
  143. /* ^data ^tail ^cur ^size */
  144. len_total += shbuf_size;
  145. }
  146. copy = xmalloc(len_total + 1);
  147. if (len_first_part < 0) {
  148. /* message wraps (see above) */
  149. len_first_part = shbuf_size - cur;
  150. memcpy(copy + len_first_part, shbuf_data, shbuf_tail);
  151. }
  152. memcpy(copy, shbuf_data + cur, len_first_part);
  153. copy[len_total] = '\0';
  154. cur = shbuf_tail;
  155. #else
  156. while (cur != shbuf_tail) {
  157. fputs(shbuf_data + cur, stdout);
  158. cur += strlen(shbuf_data + cur) + 1;
  159. if (cur >= shbuf_size)
  160. cur = 0;
  161. }
  162. #endif
  163. unlock:
  164. /* release the lock on the log chain */
  165. sem_up(log_semid);
  166. #if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING
  167. for (i = 0; i < len_total; i += strlen(copy + i) + 1) {
  168. fputs(copy + i, stdout);
  169. }
  170. free(copy);
  171. #endif
  172. fflush_all();
  173. } while (follow);
  174. /* shmdt(shbuf); - on Linux, shmdt is not mandatory on exit */
  175. fflush_stdout_and_exit(EXIT_SUCCESS);
  176. }