2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <sys/types.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
28 #include <libubox/blobmsg_json.h>
29 #include <libubox/usock.h>
30 #include <libubox/uloop.h>
48 static const struct blobmsg_policy log_policy
[] = {
49 [LOG_MSG
] = { .name
= "msg", .type
= BLOBMSG_TYPE_STRING
},
50 [LOG_ID
] = { .name
= "id", .type
= BLOBMSG_TYPE_INT32
},
51 [LOG_PRIO
] = { .name
= "priority", .type
= BLOBMSG_TYPE_INT32
},
52 [LOG_SOURCE
] = { .name
= "source", .type
= BLOBMSG_TYPE_INT32
},
53 [LOG_TIME
] = { .name
= "time", .type
= BLOBMSG_TYPE_INT64
},
56 static struct ubus_subscriber log_event
;
57 static struct uloop_timeout retry
;
58 static struct uloop_fd sender
;
59 static const char *log_file
, *log_ip
, *log_port
, *pid_file
;
60 static int log_type
= LOG_STDOUT
;
61 static int log_size
, log_udp
;
63 static void log_handle_reconnect(struct uloop_timeout
*timeout
)
65 sender
.fd
= usock((log_udp
) ? (USOCK_UDP
) : (USOCK_TCP
), log_ip
, log_port
);
67 fprintf(stderr
, "failed to connect: %s\n", strerror(errno
));
68 uloop_timeout_set(&retry
, 1000);
70 uloop_fd_add(&sender
, ULOOP_READ
);
71 syslog(0, "Logread connected to %s:%s\n", log_ip
, log_port
);
75 static void log_handle_remove(struct ubus_context
*ctx
, struct ubus_subscriber
*s
,
78 fprintf(stderr
, "Object %08x went away\n", id
);
81 static void log_handle_fd(struct uloop_fd
*u
, unsigned int events
)
87 uloop_timeout_set(&retry
, 1000);
91 static int log_notify(struct ubus_context
*ctx
, struct ubus_object
*obj
,
92 struct ubus_request_data
*req
, const char *method
,
93 struct blob_attr
*msg
)
95 struct blob_attr
*tb
[__LOG_MAX
];
106 blobmsg_parse(log_policy
, ARRAY_SIZE(log_policy
), tb
, blob_data(msg
), blob_len(msg
));
107 if (!tb
[LOG_ID
] || !tb
[LOG_PRIO
] || !tb
[LOG_SOURCE
] || !tb
[LOG_TIME
])
110 if ((log_type
== LOG_FILE
) && log_size
&& (!stat(log_file
, &s
)) && (s
.st_size
> log_size
)) {
111 char *old
= malloc(strlen(log_file
) + 5);
115 sprintf(old
, "%s.old", log_file
);
116 rename(log_file
, old
);
119 sender
.fd
= open(log_file
, O_CREAT
| O_WRONLY
| O_APPEND
, 0600);
121 // fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
126 t
= blobmsg_get_u64(tb
[LOG_TIME
]) / 1000;
128 p
= blobmsg_get_u32(tb
[LOG_PRIO
]);
129 c
[strlen(c
) - 1] = '\0';
130 str
= blobmsg_format_json(msg
, true);
131 if (log_type
== LOG_NET
) {
134 snprintf(buf
, sizeof(buf
), "%s%s\n",
135 (blobmsg_get_u32(tb
[LOG_SOURCE
])) ? ("") : ("kernel: "),
138 err
= write(sender
.fd
, buf
, strlen(buf
));
140 err
= send(sender
.fd
, buf
, strlen(buf
), 0);
143 syslog(0, "failed to send log data to %s:%s via %s\n",
144 log_ip
, log_port
, (log_udp
) ? ("udp") : ("tcp"));
145 uloop_fd_delete(&sender
);
148 uloop_timeout_set(&retry
, 1000);
151 snprintf(buf
, sizeof(buf
), "%s %s.%s%s %s\n",
152 c
, facilitynames
[LOG_FAC(p
)].c_name
, prioritynames
[LOG_PRI(p
)].c_name
,
153 (blobmsg_get_u32(tb
[LOG_SOURCE
])) ? ("") : (" kernel:"),
155 write(sender
.fd
, buf
, strlen(buf
));
159 if (log_type
== LOG_FILE
)
165 static void follow_log(struct ubus_context
*ctx
, int id
)
170 signal(SIGPIPE
, SIG_IGN
);
173 fp
= fopen(pid_file
, "w+");
175 fprintf(fp
, "%d", getpid());
183 log_event
.remove_cb
= log_handle_remove
;
184 log_event
.cb
= log_notify
;
185 ret
= ubus_register_subscriber(ctx
, &log_event
);
187 fprintf(stderr
, "Failed to add watch handler: %s\n", ubus_strerror(ret
));
189 ret
= ubus_subscribe(ctx
, &log_event
, id
);
191 fprintf(stderr
, "Failed to add watch handler: %s\n", ubus_strerror(ret
));
193 if (log_ip
&& log_port
) {
194 openlog("logread", LOG_PID
, LOG_DAEMON
);
196 sender
.cb
= log_handle_fd
;
197 retry
.cb
= log_handle_reconnect
;
198 uloop_timeout_set(&retry
, 1000);
199 } else if (log_file
) {
201 sender
.fd
= open(log_file
, O_CREAT
| O_WRONLY
| O_APPEND
, 0600);
203 fprintf(stderr
, "failed to open %s: %s\n", log_file
, strerror(errno
));
207 sender
.fd
= STDOUT_FILENO
;
220 static const struct blobmsg_policy read_policy
[] = {
221 [READ_LINE
] = { .name
= "lines", .type
= BLOBMSG_TYPE_ARRAY
},
224 static void read_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
226 struct blob_attr
*cur
;
227 struct blob_attr
*_tb
[__READ_MAX
];
234 blobmsg_parse(read_policy
, ARRAY_SIZE(read_policy
), _tb
, blob_data(msg
), blob_len(msg
));
237 blobmsg_for_each_attr(cur
, _tb
[READ_LINE
], rem
) {
238 struct blob_attr
*tb
[__LOG_MAX
];
242 if (blobmsg_type(cur
) != BLOBMSG_TYPE_TABLE
)
245 blobmsg_parse(log_policy
, ARRAY_SIZE(log_policy
), tb
, blobmsg_data(cur
), blobmsg_data_len(cur
));
246 if (!tb
[LOG_MSG
] || !tb
[LOG_ID
] || !tb
[LOG_PRIO
] || !tb
[LOG_SOURCE
] || !tb
[LOG_TIME
])
249 t
= blobmsg_get_u64(tb
[LOG_TIME
]);
250 p
= blobmsg_get_u32(tb
[LOG_PRIO
]);
252 c
[strlen(c
) - 1] = '\0';
254 printf("%s %s.%s%s %s\n",
255 c
, facilitynames
[LOG_FAC(p
)].c_name
, prioritynames
[LOG_PRI(p
)].c_name
,
256 (blobmsg_get_u32(tb
[LOG_SOURCE
])) ? ("") : (" kernel:"),
257 blobmsg_get_string(tb
[LOG_MSG
]));
261 static int usage(const char *prog
)
263 fprintf(stderr
, "Usage: %s [options]\n"
265 " -s <path> Path to ubus socket\n"
266 " -l <count> Got only the last 'count' messages\n"
267 " -r <server> <port> Stream message to a server\n"
268 " -F <file> Log file\n"
269 " -S <bytes> Log size\n"
270 " -p <file> PID file\n"
271 " -f Follow log messages\n"
272 " -u Use UDP as the protocol\n"
277 int main(int argc
, char **argv
)
279 struct ubus_context
*ctx
;
281 const char *ubus_socket
= NULL
;
282 int ch
, ret
, subscribe
= 0, lines
= 0;
283 static struct blob_buf b
;
285 while ((ch
= getopt(argc
, argv
, "ufcs:l:r:F:p:S:")) != -1) {
291 ubus_socket
= optarg
;
295 log_port
= argv
[optind
++];
307 lines
= atoi(optarg
);
310 log_size
= atoi(optarg
);
320 ctx
= ubus_connect(ubus_socket
);
322 fprintf(stderr
, "Failed to connect to ubus\n");
326 ret
= ubus_lookup_id(ctx
, "log", &id
);
328 fprintf(stderr
, "Failed to find log object: %s\n", ubus_strerror(ret
));
330 if (!subscribe
|| lines
) {
331 blob_buf_init(&b
, 0);
333 blobmsg_add_u32(&b
, "lines", lines
);
334 ubus_invoke(ctx
, id
, "read", b
.head
, read_cb
, 0, 3000);