Ubox
OpenWrt core utilities
logread.c File Reference
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <regex.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <syslog.h>
#include <libubox/ustream.h>
#include <libubox/blobmsg_json.h>
#include <libubox/usock.h>
#include <libubox/uloop.h>
#include "libubus.h"

Go to the source code of this file.

Macros

#define SYSLOG_NAMES
 
#define LOGD_CONNECT_RETRY   10
 

Enumerations

enum  { LOG_STDOUT , LOG_FILE , LOG_NET }
 
enum  {
  LOG_MSG , LOG_ID , LOG_PRIO , LOG_SOURCE ,
  LOG_TIME , __LOG_MAX
}
 

Functions

static int check_facility_filter (int f)
 
static const char * getcodetext (int value, CODE *codetable)
 
static void log_handle_reconnect (struct uloop_timeout *timeout)
 
static void log_handle_fd (struct uloop_fd *u, unsigned int events)
 
static int log_notify (struct blob_attr *msg)
 
static int usage (const char *prog)
 
static void logread_fd_data_cb (struct ustream *s, int bytes)
 
static void logread_fd_state_cb (struct ustream *s)
 
static void logread_fd_cb (struct ubus_request *req, int fd)
 
static void logread_setup_output (void)
 
int main (int argc, char **argv)
 

Variables

static const struct blobmsg_policy log_policy []
 
static struct uloop_timeout retry
 
static struct uloop_fd sender
 
static regex_t regexp_preg
 
static const char * log_file
 
static const char * log_ip
 
static const char * log_port
 
static const char * log_prefix
 
static const char * pid_file
 
static const char * hostname
 
static const char * regexp_pattern
 
static int log_type = LOG_STDOUT
 
static int log_size
 
static int log_udp
 
static int log_follow
 
static int log_trailer_null = 0
 
static int log_timestamp
 
static int logd_conn_tries = 10
 
static int facility_include
 
static int facility_exclude
 

Macro Definition Documentation

◆ LOGD_CONNECT_RETRY

#define LOGD_CONNECT_RETRY   10

Definition at line 36 of file logread.c.

◆ SYSLOG_NAMES

#define SYSLOG_NAMES

Definition at line 26 of file logread.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
LOG_STDOUT 
LOG_FILE 
LOG_NET 

Definition at line 38 of file logread.c.

38  {
39  LOG_STDOUT,
40  LOG_FILE,
41  LOG_NET,
42 };
@ LOG_FILE
Definition: logread.c:40
@ LOG_NET
Definition: logread.c:41
@ LOG_STDOUT
Definition: logread.c:39

◆ anonymous enum

anonymous enum
Enumerator
LOG_MSG 
LOG_ID 
LOG_PRIO 
LOG_SOURCE 
LOG_TIME 
__LOG_MAX 

Definition at line 44 of file logread.c.

44  {
45  LOG_MSG,
46  LOG_ID,
47  LOG_PRIO,
48  LOG_SOURCE,
49  LOG_TIME,
50  __LOG_MAX
51 };
@ LOG_TIME
Definition: logread.c:49
@ __LOG_MAX
Definition: logread.c:50
@ LOG_MSG
Definition: logread.c:45
@ LOG_PRIO
Definition: logread.c:47
@ LOG_ID
Definition: logread.c:46
@ LOG_SOURCE
Definition: logread.c:48

Function Documentation

◆ check_facility_filter()

static int check_facility_filter ( int  f)
static

Definition at line 73 of file logread.c.

74 {
75  if (facility_include)
76  return !!(facility_include & (1 << f));
77  if (facility_exclude)
78  return !(facility_exclude & (1 << f));
79  return 1;
80 }
static int facility_exclude
Definition: logread.c:70
static int facility_include
Definition: logread.c:69
Here is the caller graph for this function:

◆ getcodetext()

static const char* getcodetext ( int  value,
CODE *  codetable 
)
static

Definition at line 82 of file logread.c.

82  {
83  CODE *i;
84 
85  if (value >= 0)
86  for (i = codetable; i->c_val != -1; i++)
87  if (i->c_val == value)
88  return (i->c_name);
89  return "<unknown>";
90 };
Here is the caller graph for this function:

◆ log_handle_fd()

static void log_handle_fd ( struct uloop_fd *  u,
unsigned int  events 
)
static

Definition at line 110 of file logread.c.

111 {
112  if (u->eof) {
113  uloop_fd_delete(u);
114  close(sender.fd);
115  sender.fd = -1;
116  uloop_timeout_set(&retry, 1000);
117  }
118 }
static struct uloop_fd sender
Definition: logread.c:62
static struct uloop_timeout retry
Definition: logread.c:61
Here is the caller graph for this function:

◆ log_handle_reconnect()

static void log_handle_reconnect ( struct uloop_timeout *  timeout)
static

Definition at line 92 of file logread.c.

93 {
94  sender.fd = usock((log_udp) ? (USOCK_UDP) : (USOCK_TCP), log_ip, log_port);
95  if (sender.fd < 0) {
96  fprintf(stderr, "failed to connect: %m\n");
97  uloop_timeout_set(&retry, 1000);
98  } else {
99  uloop_fd_add(&sender, ULOOP_READ);
100 
101  if (log_udp < 2)
102  syslog(LOG_INFO, "Logread connected to %s:%s via %s\n",
103  log_ip, log_port, (log_udp) ? ("udp") : ("tcp"));
104 
105  if (log_udp == 1)
106  ++log_udp;
107  }
108 }
static const char * log_port
Definition: logread.c:64
static const char * log_ip
Definition: logread.c:64
static int log_udp
Definition: logread.c:66
Here is the caller graph for this function:

◆ log_notify()

static int log_notify ( struct blob_attr *  msg)
static

Definition at line 120 of file logread.c.

121 {
122  struct blob_attr *tb[__LOG_MAX];
123  struct stat s;
124  char buf[LOG_LINE_SIZE + 128];
125  char buf_ts[32];
126  uint32_t p;
127  time_t t;
128  uint32_t t_ms = 0;
129  char *c, *m;
130  int ret = 0;
131 
132  if (sender.fd < 0)
133  return 0;
134 
135  blobmsg_parse(log_policy, ARRAY_SIZE(log_policy), tb, blob_data(msg), blob_len(msg));
136  if (!tb[LOG_ID] || !tb[LOG_PRIO] || !tb[LOG_SOURCE] || !tb[LOG_TIME] || !tb[LOG_MSG])
137  return 1;
138 
139  if ((log_type == LOG_FILE) && log_size && (!stat(log_file, &s)) && (s.st_size > log_size)) {
140  char *old = malloc(strlen(log_file) + 5);
141 
142  close(sender.fd);
143  if (old) {
144  sprintf(old, "%s.old", log_file);
145  rename(log_file, old);
146  free(old);
147  }
148  sender.fd = open(log_file, O_CREAT | O_WRONLY | O_APPEND, 0600);
149  if (sender.fd < 0) {
150  fprintf(stderr, "failed to open %s: %m\n", log_file);
151  exit(-1);
152  }
153  }
154  p = blobmsg_get_u32(tb[LOG_PRIO]);
155 
156  if (!check_facility_filter(LOG_FAC(p)))
157  return 0;
158 
159  m = blobmsg_get_string(tb[LOG_MSG]);
160  if (regexp_pattern &&
161  regexec(&regexp_preg, m, 0, NULL, 0) == REG_NOMATCH)
162  return 0;
163  t = blobmsg_get_u64(tb[LOG_TIME]) / 1000;
164  if (log_timestamp) {
165  t_ms = blobmsg_get_u64(tb[LOG_TIME]) % 1000;
166  snprintf(buf_ts, sizeof(buf_ts), "[%lu.%03u] ",
167  (unsigned long)t, t_ms);
168  }
169  c = ctime(&t);
170  c[strlen(c) - 1] = '\0';
171 
172  if (log_type == LOG_NET) {
173  int err;
174 
175  snprintf(buf, sizeof(buf), "<%u>", p);
176  strncat(buf, c + 4, 16);
177  if (log_timestamp) {
178  strncat(buf, buf_ts, sizeof(buf) - strlen(buf) - 1);
179  }
180  if (hostname) {
181  strncat(buf, hostname, sizeof(buf) - strlen(buf) - 1);
182  strncat(buf, " ", sizeof(buf) - strlen(buf) - 1);
183  }
184  if (log_prefix) {
185  strncat(buf, log_prefix, sizeof(buf) - strlen(buf) - 1);
186  strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1);
187  }
188  if (blobmsg_get_u32(tb[LOG_SOURCE]) == SOURCE_KLOG)
189  strncat(buf, "kernel: ", sizeof(buf) - strlen(buf) - 1);
190  strncat(buf, m, sizeof(buf) - strlen(buf) - 1);
191  if (log_udp)
192  err = write(sender.fd, buf, strlen(buf));
193  else {
194  size_t buflen = strlen(buf);
195  if (!log_trailer_null)
196  buf[buflen] = '\n';
197  err = send(sender.fd, buf, buflen + 1, 0);
198  }
199 
200  if (err < 0) {
201  syslog(LOG_INFO, "Failed to send log data to %s:%s via %s\n",
202  log_ip, log_port, (log_udp) ? ("udp") : ("tcp"));
203  uloop_fd_delete(&sender);
204  close(sender.fd);
205  sender.fd = -1;
206  uloop_timeout_set(&retry, 1000);
207  }
208  } else {
209  snprintf(buf, sizeof(buf), "%s %s%s.%s%s %s\n",
210  c, log_timestamp ? buf_ts : "",
211  getcodetext(LOG_FAC(p) << 3, facilitynames),
212  getcodetext(LOG_PRI(p), prioritynames),
213  (blobmsg_get_u32(tb[LOG_SOURCE])) ? ("") : (" kernel:"), m);
214  ret = write(sender.fd, buf, strlen(buf));
215  }
216 
217  if (log_type == LOG_FILE)
218  fsync(sender.fd);
219 
220  return ret;
221 }
static const char * getcodetext(int value, CODE *codetable)
Definition: logread.c:82
static int log_size
Definition: logread.c:66
static regex_t regexp_preg
Definition: logread.c:63
static int check_facility_filter(int f)
Definition: logread.c:73
static const char * regexp_pattern
Definition: logread.c:64
static int log_timestamp
Definition: logread.c:67
static const char * hostname
Definition: logread.c:64
static const char * log_prefix
Definition: logread.c:64
static const struct blobmsg_policy log_policy[]
Definition: logread.c:53
static int log_type
Definition: logread.c:65
static int log_trailer_null
Definition: logread.c:66
static const char * log_file
Definition: logread.c:64
#define LOG_LINE_SIZE
Definition: syslog.h:17
@ SOURCE_KLOG
Definition: syslog.h:22
Here is the call graph for this function:
Here is the caller graph for this function:

◆ logread_fd_cb()

static void logread_fd_cb ( struct ubus_request *  req,
int  fd 
)
static

Definition at line 272 of file logread.c.

273 {
274  static struct ustream_fd test_fd;
275 
276  memset(&test_fd, 0, sizeof(test_fd));
277 
278  test_fd.stream.notify_read = logread_fd_data_cb;
279  test_fd.stream.notify_state = logread_fd_state_cb;
280  ustream_fd_init(&test_fd, fd);
281 }
static void logread_fd_state_cb(struct ustream *s)
Definition: logread.c:265
static void logread_fd_data_cb(struct ustream *s, int bytes)
Definition: logread.c:246
Here is the call graph for this function:
Here is the caller graph for this function:

◆ logread_fd_data_cb()

static void logread_fd_data_cb ( struct ustream *  s,
int  bytes 
)
static

Definition at line 246 of file logread.c.

247 {
248  while (true) {
249  struct blob_attr *a;
250  int len, cur_len;
251 
252  a = (void*) ustream_get_read_buf(s, &len);
253  if (len < sizeof(*a))
254  break;
255 
256  cur_len = blob_len(a) + sizeof(*a);
257  if (len < cur_len)
258  break;
259 
260  log_notify(a);
261  ustream_consume(s, cur_len);
262  }
263 }
static int log_notify(struct blob_attr *msg)
Definition: logread.c:120
Here is the call graph for this function:
Here is the caller graph for this function:

◆ logread_fd_state_cb()

static void logread_fd_state_cb ( struct ustream *  s)
static

Definition at line 265 of file logread.c.

266 {
267  if (log_follow)
269  uloop_end();
270 }
static int log_follow
Definition: logread.c:66
#define LOGD_CONNECT_RETRY
Definition: logread.c:36
static int logd_conn_tries
Definition: logread.c:68
Here is the caller graph for this function:

◆ logread_setup_output()

static void logread_setup_output ( void  )
static

Definition at line 283 of file logread.c.

284 {
285  if (sender.fd || sender.cb)
286  return;
287 
288  if (log_ip && log_port) {
289  openlog("logread", LOG_PID, LOG_DAEMON);
290  log_type = LOG_NET;
291  sender.cb = log_handle_fd;
293  uloop_timeout_set(&retry, 1000);
294  } else if (log_file) {
295  log_type = LOG_FILE;
296  sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600);
297  if (sender.fd < 0) {
298  fprintf(stderr, "failed to open %s: %m\n", log_file);
299  exit(-1);
300  }
301  } else {
302  sender.fd = STDOUT_FILENO;
303  }
304 }
static void log_handle_reconnect(struct uloop_timeout *timeout)
Definition: logread.c:92
static void log_handle_fd(struct uloop_fd *u, unsigned int events)
Definition: logread.c:110
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 306 of file logread.c.

307 {
308  struct ubus_context *ctx;
309  uint32_t id;
310  const char *ubus_socket = NULL;
311  int ch, ret, lines = 0;
312  static struct blob_buf b;
313 
314  signal(SIGPIPE, SIG_IGN);
315 
316  while ((ch = getopt(argc, argv, "u0fcs:l:z:Z:r:F:p:S:P:h:e:t")) != -1) {
317  switch (ch) {
318  case 'u':
319  log_udp = 1;
320  break;
321  case '0':
322  log_trailer_null = 1;
323  break;
324  case 's':
325  ubus_socket = optarg;
326  break;
327  case 'r':
328  log_ip = optarg++;
329  log_port = argv[optind++];
330  break;
331  case 'F':
332  log_file = optarg;
333  break;
334  case 'p':
335  pid_file = optarg;
336  break;
337  case 'P':
338  log_prefix = optarg;
339  break;
340  case 'f':
341  log_follow = 1;
342  break;
343  case 'l':
344  lines = atoi(optarg);
345  break;
346  case 'z':
347  id = strtoul(optarg, NULL, 0) & 0x1f;
348  facility_include |= (1 << id);
349  break;
350  case 'Z':
351  id = strtoul(optarg, NULL, 0) & 0x1f;
352  facility_exclude |= (1 << id);
353  break;
354  case 'S':
355  log_size = atoi(optarg);
356  if (log_size < 1)
357  log_size = 1;
358  log_size *= 1024;
359  break;
360  case 'h':
361  hostname = optarg;
362  break;
363  case 'e':
364  if (!regcomp(&regexp_preg, optarg, REG_NOSUB)) {
365  regexp_pattern = optarg;
366  }
367  break;
368  case 't':
369  log_timestamp = 1;
370  break;
371  default:
372  return usage(*argv);
373  }
374  }
375  uloop_init();
376 
377  ctx = ubus_connect(ubus_socket);
378  if (!ctx) {
379  fprintf(stderr, "Failed to connect to ubus\n");
380  return -1;
381  }
382  ubus_add_uloop(ctx);
383 
384  if (log_follow && pid_file) {
385  FILE *fp = fopen(pid_file, "w+");
386  if (fp) {
387  fprintf(fp, "%d", getpid());
388  fclose(fp);
389  }
390  }
391 
392  blob_buf_init(&b, 0);
393  blobmsg_add_u8(&b, "stream", 1);
394  blobmsg_add_u8(&b, "oneshot", !log_follow);
395  if (lines)
396  blobmsg_add_u32(&b, "lines", lines);
397  else if (log_follow)
398  blobmsg_add_u32(&b, "lines", 0);
399 
400  /* ugly ugly ugly ... we need a real reconnect logic */
401  do {
402  struct ubus_request req = { 0 };
403 
404  ret = ubus_lookup_id(ctx, "log", &id);
405  if (ret) {
406  fprintf(stderr, "Failed to find log object: %s\n", ubus_strerror(ret));
407  sleep(1);
408  continue;
409  }
410  logd_conn_tries = 0;
412 
413  ubus_invoke_async(ctx, id, "read", b.head, &req);
414  req.fd_cb = logread_fd_cb;
415  ubus_complete_request_async(ctx, &req);
416 
417  uloop_run();
418 
419  } while (logd_conn_tries--);
420 
421  ubus_free(ctx);
422  uloop_done();
423 
424  if (log_follow && pid_file)
425  unlink(pid_file);
426 
427  return ret;
428 }
static struct blob_buf b
Definition: logd.c:33
static const char * pid_file
Definition: logread.c:64
static void logread_fd_cb(struct ubus_request *req, int fd)
Definition: logread.c:272
static void logread_setup_output(void)
Definition: logread.c:283
static int usage(const char *prog)
Definition: logread.c:223
static struct ubus_context * ctx
Definition: lsbloader.c:43
Here is the call graph for this function:

◆ usage()

static int usage ( const char *  prog)
static

Definition at line 223 of file logread.c.

224 {
225  fprintf(stderr, "Usage: %s [options]\n"
226  "Options:\n"
227  " -s <path> Path to ubus socket\n"
228  " -l <count> Got only the last 'count' messages\n"
229  " -e <pattern> Filter messages with a regexp\n"
230  " -r <server> <port> Stream message to a server\n"
231  " -F <file> Log file\n"
232  " -S <bytes> Log size\n"
233  " -p <file> PID file\n"
234  " -h <hostname> Add hostname to the message\n"
235  " -P <prefix> Prefix custom text to streamed messages\n"
236  " -z <facility> handle only messages with given facility (0-23), repeatable\n"
237  " -Z <facility> ignore messages with given facility (0-23), repeatable\n"
238  " -f Follow log messages\n"
239  " -u Use UDP as the protocol\n"
240  " -t Add an extra timestamp\n"
241  " -0 Use \\0 instead of \\n as trailer when using TCP\n"
242  "\n", prog);
243  return 1;
244 }
Here is the caller graph for this function:

Variable Documentation

◆ facility_exclude

int facility_exclude
static

Definition at line 70 of file logread.c.

◆ facility_include

int facility_include
static

Definition at line 69 of file logread.c.

◆ hostname

const char * hostname
static

Definition at line 64 of file logread.c.

◆ log_file

const char* log_file
static

Definition at line 64 of file logread.c.

◆ log_follow

int log_follow
static

Definition at line 66 of file logread.c.

◆ log_ip

const char * log_ip
static

Definition at line 64 of file logread.c.

◆ log_policy

const struct blobmsg_policy log_policy[]
static
Initial value:
= {
[LOG_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_STRING },
[LOG_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
[LOG_PRIO] = { .name = "priority", .type = BLOBMSG_TYPE_INT32 },
[LOG_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_INT32 },
[LOG_TIME] = { .name = "time", .type = BLOBMSG_TYPE_INT64 },
}

Definition at line 1 of file logread.c.

◆ log_port

const char * log_port
static

Definition at line 64 of file logread.c.

◆ log_prefix

const char * log_prefix
static

Definition at line 64 of file logread.c.

◆ log_size

int log_size
static

Definition at line 66 of file logread.c.

◆ log_timestamp

int log_timestamp
static

Definition at line 67 of file logread.c.

◆ log_trailer_null

int log_trailer_null = 0
static

Definition at line 66 of file logread.c.

◆ log_type

int log_type = LOG_STDOUT
static

Definition at line 65 of file logread.c.

◆ log_udp

int log_udp
static

Definition at line 66 of file logread.c.

◆ logd_conn_tries

int logd_conn_tries = 10
static

Definition at line 68 of file logread.c.

◆ pid_file

const char * pid_file
static

Definition at line 64 of file logread.c.

◆ regexp_pattern

const char * regexp_pattern
static

Definition at line 64 of file logread.c.

◆ regexp_preg

regex_t regexp_preg
static

Definition at line 63 of file logread.c.

◆ retry

struct uloop_timeout retry
static

Definition at line 1 of file logread.c.

◆ sender

struct uloop_fd sender
static

Definition at line 1 of file logread.c.