source: MondoRescue/branches/3.3/mindi-busybox/sysklogd/logread.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.1 KB
Line 
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//config:config LOGREAD
12//config: bool "logread"
13//config: default y
14//config: depends on FEATURE_IPC_SYSLOG
15//config: help
16//config: If you enabled Circular Buffer support, you almost
17//config: certainly want to enable this feature as well. This
18//config: utility will allow you to read the messages that are
19//config: stored in the syslogd circular buffer.
20//config:
21//config:config FEATURE_LOGREAD_REDUCED_LOCKING
22//config: bool "Double buffering"
23//config: default y
24//config: depends on LOGREAD
25//config: help
26//config: 'logread' ouput to slow serial terminals can have
27//config: side effects on syslog because of the semaphore.
28//config: This option make logread to double buffer copy
29//config: from circular buffer, minimizing semaphore
30//config: contention at some minor memory expense.
31//config:
32
33//applet:IF_LOGREAD(APPLET(logread, BB_DIR_SBIN, BB_SUID_DROP))
34
35//kbuild:lib-$(CONFIG_LOGREAD) += logread.o
36
37//usage:#define logread_trivial_usage
38//usage: "[-fF]"
39//usage:#define logread_full_usage "\n\n"
40//usage: "Show messages in syslogd's circular buffer\n"
41//usage: "\n -f Output data as log grows"
42//usage: "\n -F Same as -f, but dump buffer first"
43
44#include "libbb.h"
45#include "common_bufsiz.h"
46#include <sys/ipc.h>
47#include <sys/sem.h>
48#include <sys/shm.h>
49
50#define DEBUG 0
51
52/* our shared key (syslogd.c and logread.c must be in sync) */
53enum { KEY_ID = 0x414e4547 }; /* "GENA" */
54
55struct shbuf_ds {
56 int32_t size; // size of data - 1
57 int32_t tail; // end of message list
58 char data[1]; // messages
59};
60
61static const struct sembuf init_sem[3] = {
62 {0, -1, IPC_NOWAIT | SEM_UNDO},
63 {1, 0}, {0, +1, SEM_UNDO}
64};
65
66struct globals {
67 struct sembuf SMrup[1]; // {0, -1, IPC_NOWAIT | SEM_UNDO},
68 struct sembuf SMrdn[2]; // {1, 0}, {0, +1, SEM_UNDO}
69 struct shbuf_ds *shbuf;
70} FIX_ALIASING;
71#define G (*(struct globals*)bb_common_bufsiz1)
72#define SMrup (G.SMrup)
73#define SMrdn (G.SMrdn)
74#define shbuf (G.shbuf)
75#define INIT_G() do { \
76 setup_common_bufsiz(); \
77 memcpy(SMrup, init_sem, sizeof(init_sem)); \
78} while (0)
79
80#if 0
81static void error_exit(const char *str) NORETURN;
82static void error_exit(const char *str)
83{
84 /* Release all acquired resources */
85 shmdt(shbuf);
86 bb_perror_msg_and_die(str);
87}
88#else
89/* On Linux, shmdt is not mandatory on exit */
90# define error_exit(str) bb_perror_msg_and_die(str)
91#endif
92
93/*
94 * sem_up - up()'s a semaphore.
95 */
96static void sem_up(int semid)
97{
98 if (semop(semid, SMrup, 1) == -1)
99 error_exit("semop[SMrup]");
100}
101
102static void interrupted(int sig)
103{
104 /* shmdt(shbuf); - on Linux, shmdt is not mandatory on exit */
105 kill_myself_with_sig(sig);
106}
107
108int logread_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
109int logread_main(int argc UNUSED_PARAM, char **argv)
110{
111 unsigned cur;
112 int log_semid; /* ipc semaphore id */
113 int log_shmid; /* ipc shared memory id */
114 int follow = getopt32(argv, "fF");
115
116 INIT_G();
117
118 log_shmid = shmget(KEY_ID, 0, 0);
119 if (log_shmid == -1)
120 bb_perror_msg_and_die("can't %s syslogd buffer", "find");
121
122 /* Attach shared memory to our char* */
123 shbuf = shmat(log_shmid, NULL, SHM_RDONLY);
124 if (shbuf == NULL)
125 bb_perror_msg_and_die("can't %s syslogd buffer", "access");
126
127 log_semid = semget(KEY_ID, 0, 0);
128 if (log_semid == -1)
129 error_exit("can't get access to semaphores for syslogd buffer");
130
131 bb_signals(BB_FATAL_SIGS, interrupted);
132
133 /* Suppose atomic memory read */
134 /* Max possible value for tail is shbuf->size - 1 */
135 cur = shbuf->tail;
136
137 /* Loop for -f or -F, one pass otherwise */
138 do {
139 unsigned shbuf_size;
140 unsigned shbuf_tail;
141 const char *shbuf_data;
142#if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING
143 int i;
144 int len_first_part;
145 int len_total = len_total; /* for gcc */
146 char *copy = copy; /* for gcc */
147#endif
148 if (semop(log_semid, SMrdn, 2) == -1)
149 error_exit("semop[SMrdn]");
150
151 /* Copy the info, helps gcc to realize that it doesn't change */
152 shbuf_size = shbuf->size;
153 shbuf_tail = shbuf->tail;
154 shbuf_data = shbuf->data; /* pointer! */
155
156 if (DEBUG)
157 printf("cur:%u tail:%u size:%u\n",
158 cur, shbuf_tail, shbuf_size);
159
160 if (!(follow & 1)) { /* not -f */
161 /* if -F, "convert" it to -f, so that we dont
162 * dump the entire buffer on each iteration
163 */
164 follow >>= 1;
165
166 /* advance to oldest complete message */
167 /* find NUL */
168 cur += strlen(shbuf_data + cur);
169 if (cur >= shbuf_size) { /* last byte in buffer? */
170 cur = strnlen(shbuf_data, shbuf_tail);
171 if (cur == shbuf_tail)
172 goto unlock; /* no complete messages */
173 }
174 /* advance to first byte of the message */
175 cur++;
176 if (cur >= shbuf_size) /* last byte in buffer? */
177 cur = 0;
178 } else { /* -f */
179 if (cur == shbuf_tail) {
180 sem_up(log_semid);
181 fflush_all();
182 sleep(1); /* TODO: replace me with a sleep_on */
183 continue;
184 }
185 }
186
187 /* Read from cur to tail */
188#if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING
189 len_first_part = len_total = shbuf_tail - cur;
190 if (len_total < 0) {
191 /* message wraps: */
192 /* [SECOND PART.........FIRST PART] */
193 /* ^data ^tail ^cur ^size */
194 len_total += shbuf_size;
195 }
196 copy = xmalloc(len_total + 1);
197 if (len_first_part < 0) {
198 /* message wraps (see above) */
199 len_first_part = shbuf_size - cur;
200 memcpy(copy + len_first_part, shbuf_data, shbuf_tail);
201 }
202 memcpy(copy, shbuf_data + cur, len_first_part);
203 copy[len_total] = '\0';
204 cur = shbuf_tail;
205#else
206 while (cur != shbuf_tail) {
207 fputs(shbuf_data + cur, stdout);
208 cur += strlen(shbuf_data + cur) + 1;
209 if (cur >= shbuf_size)
210 cur = 0;
211 }
212#endif
213 unlock:
214 /* release the lock on the log chain */
215 sem_up(log_semid);
216
217#if ENABLE_FEATURE_LOGREAD_REDUCED_LOCKING
218 for (i = 0; i < len_total; i += strlen(copy + i) + 1) {
219 fputs(copy + i, stdout);
220 }
221 free(copy);
222#endif
223 fflush_all();
224 } while (follow);
225
226 /* shmdt(shbuf); - on Linux, shmdt is not mandatory on exit */
227
228 fflush_stdout_and_exit(EXIT_SUCCESS);
229}
Note: See TracBrowser for help on using the repository browser.