logread.c 4.2 KB

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