Skip to content

Commit 1730bb4

Browse files
author
Richard Young
committed
Improved support for logrotate daemon.
1. Treats sighup as signal to close and reopen log file 2. Candump only supports autogenerated log file name by default. For use with logrotation daemon it expects consistent filename. I updated -l option to accept optional filename. 3. Since interface is a required argument, getopt skips final arg. Made -l take optional filename. Without filename maintains existing behavior. 4. Since sighup can interupt the select system call, now checking epoll error code for interupted syscal and logfile enabled. If those conditions are met, the errorcode is non critical.
1 parent 682e01a commit 1730bb4

File tree

1 file changed

+174
-37
lines changed

1 file changed

+174
-37
lines changed

Diff for: candump.c

+174-37
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,18 @@ static const int canfd_on = 1;
116116
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
117117
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
118118

119+
#define MAXLOGNAMESZ 100
120+
static FILE *logfile = NULL;
121+
static char log_filename[MAXLOGNAMESZ];
122+
123+
static unsigned char silent = SILENT_INI;
124+
119125
extern int optind, opterr, optopt;
120126

121127
static volatile int running = 1;
128+
static volatile int flag_reopen_file;
129+
static int is_auto_log_name;
130+
static volatile unsigned long sighup_count;
122131

123132
static void print_usage(char *prg)
124133
{
@@ -133,7 +142,7 @@ static void print_usage(char *prg)
133142
fprintf(stderr, " -a (enable additional ASCII output)\n");
134143
fprintf(stderr, " -S (swap byte order in printed CAN data[] - marked with '%c' )\n", SWAP_DELIMITER);
135144
fprintf(stderr, " -s <level> (silent mode - %d: off (default) %d: animation %d: silent)\n", SILENT_OFF, SILENT_ANI, SILENT_ON);
136-
fprintf(stderr, " -l (log CAN-frames into file. Sets '-s %d' by default)\n", SILENT_ON);
145+
fprintf(stderr, " -l <name> (log CAN-frames into file. Sets '-s %d' by default)\n", SILENT_ON);
137146
fprintf(stderr, " -L (use log file format on stdout)\n");
138147
fprintf(stderr, " -n <count> (terminate after reception of <count> CAN frames)\n");
139148
fprintf(stderr, " -r <size> (set socket receive buffer to <size>)\n");
@@ -171,9 +180,17 @@ static void sigterm(int signo)
171180
running = 0;
172181
}
173182

174-
static int idx2dindex(int ifidx, int socket)
183+
184+
static void sighup(int signo)
175185
{
186+
if (signo == SIGHUP && running) {
187+
flag_reopen_file = 1;
188+
sighup_count++;
189+
}
190+
}
176191

192+
static int idx2dindex(int ifidx, int socket)
193+
{
177194
int i;
178195
struct ifreq ifr;
179196

@@ -221,6 +238,88 @@ static int idx2dindex(int ifidx, int socket)
221238
return i;
222239
}
223240

241+
static int sprint_auto_filename_format(char *buffer)
242+
{
243+
time_t currtime;
244+
struct tm now;
245+
246+
if (time(&currtime) == (time_t)-1) {
247+
perror("time");
248+
return 1;
249+
}
250+
251+
localtime_r(&currtime, &now);
252+
253+
sprintf(buffer, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
254+
now.tm_year + 1900,
255+
now.tm_mon + 1,
256+
now.tm_mday,
257+
now.tm_hour,
258+
now.tm_min,
259+
now.tm_sec);
260+
261+
fprintf(stderr, "Enabling Logfile '%s'\n", buffer);
262+
263+
return 0;
264+
}
265+
266+
/* opens file using global var logfile */
267+
static int open_log_file(const char *file_name)
268+
{
269+
if (silent != SILENT_ON)
270+
fprintf(stderr, "Warning: Console output active while logging!\n");
271+
272+
logfile = fopen(file_name, "w");
273+
274+
if (!logfile) {
275+
perror("logfile");
276+
return 1;
277+
}
278+
279+
return 0;
280+
}
281+
282+
static int reopen_file(FILE *file_handle)
283+
{
284+
const char *fopen_opts = (sighup_count > 0 && !is_auto_log_name) ? "a" : "w";
285+
286+
if (!file_handle)
287+
return 1;
288+
289+
if (is_auto_log_name == 1) {
290+
const int errcode = sprint_auto_filename_format(log_filename);
291+
292+
if (errcode != 0) {
293+
return 1;
294+
}
295+
}
296+
297+
logfile = freopen(log_filename, fopen_opts, file_handle);
298+
299+
flag_reopen_file = 0;
300+
301+
return logfile == 0;
302+
}
303+
304+
static int process_logname_arg(const char *arg)
305+
{
306+
if (arg != 0) {
307+
const size_t len = strnlen(arg, MAXLOGNAMESZ);
308+
309+
if (len > 0 && len < MAXLOGNAMESZ) {
310+
strncpy(log_filename, arg, MAXLOGNAMESZ - 1);
311+
} else {
312+
return 1;
313+
}
314+
is_auto_log_name = 0;
315+
} else {
316+
is_auto_log_name = 1;
317+
sprint_auto_filename_format(log_filename);
318+
}
319+
320+
return 0;
321+
}
322+
224323
int main(int argc, char **argv)
225324
{
226325
int fd_epoll;
@@ -233,7 +332,7 @@ int main(int argc, char **argv)
233332
unsigned char down_causes_exit = 1;
234333
unsigned char dropmonitor = 0;
235334
unsigned char extra_msg_info = 0;
236-
unsigned char silent = SILENT_INI;
335+
237336
unsigned char silentani = 0;
238337
unsigned char color = 0;
239338
unsigned char view = 0;
@@ -257,16 +356,33 @@ int main(int argc, char **argv)
257356
struct ifreq ifr;
258357
struct timeval tv, last_tv;
259358
int timeout_ms = -1; /* default to no timeout */
260-
FILE *logfile = NULL;
261359

262-
signal(SIGTERM, sigterm);
263-
signal(SIGHUP, sigterm);
264-
signal(SIGINT, sigterm);
360+
sigset_t sig_block_mask;
361+
sigset_t sig_mask;
362+
struct sigaction sighup_action = { .sa_flags = SA_RESTART };
363+
struct sigaction sigterm_action = { .sa_flags = SA_RESTART, .sa_handler = sigterm };
364+
365+
sigfillset(&sig_block_mask);
366+
sigemptyset(&sig_mask);
367+
368+
sighup_action.sa_mask = sig_block_mask;
369+
sigterm_action.sa_mask = sig_mask;
370+
371+
sigaction (SIGHUP, &sigterm_action, NULL);
372+
sigaction (SIGINT, &sigterm_action, NULL);
265373

266374
last_tv.tv_sec = 0;
267375
last_tv.tv_usec = 0;
268376

269-
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:he8T:?")) != -1) {
377+
int getoptargc = argc;
378+
379+
//Since interface is a required argument, we don't need to parse opt for final arg
380+
//This enabled the -l option to take an optional filename
381+
if (getoptargc > 0) {
382+
getoptargc = argc - 1;
383+
}
384+
385+
while ((opt = getopt(getoptargc, argv, ":t:HciaSs:l:DdxLn:r:he8T:?")) != -1) {
270386
switch (opt) {
271387
case 't':
272388
timestamp = optarg[0];
@@ -314,9 +430,35 @@ int main(int argc, char **argv)
314430
}
315431
break;
316432

433+
case ':': //handle flags with optional values
434+
435+
switch (optopt)
436+
{
437+
case 'l':
438+
{
439+
log = 1;
440+
441+
if (process_logname_arg(optarg) != 0) {
442+
print_usage(basename(argv[0]));
443+
exit(1);
444+
}
445+
break;
446+
}
447+
default:
448+
fprintf(stderr, "option -%c is missing a required argument\n", optopt);
449+
return EXIT_FAILURE;
450+
}
451+
break;
317452

318453
case 'l':
319454
log = 1;
455+
456+
if (process_logname_arg(optarg) != 0) {
457+
is_auto_log_name = 0;
458+
print_usage(basename(argv[0]));
459+
exit(1);
460+
}
461+
320462
break;
321463

322464
case 'D':
@@ -371,6 +513,10 @@ int main(int argc, char **argv)
371513
exit(0);
372514
}
373515

516+
/* Configure SIGHUP handler to reopen file if logging */
517+
sighup_action.sa_handler = log ? sighup : sigterm;
518+
sigaction(SIGHUP, &sighup_action, NULL);
519+
374520
if (logfrmt && view) {
375521
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP/RAWDLC options!\n");
376522
exit(0);
@@ -592,35 +738,10 @@ int main(int argc, char **argv)
592738
}
593739

594740
if (log) {
595-
time_t currtime;
596-
struct tm now;
597-
char fname[83]; /* suggested by -Wformat-overflow= */
598-
599-
if (time(&currtime) == (time_t)-1) {
600-
perror("time");
601-
return 1;
602-
}
603-
604-
localtime_r(&currtime, &now);
741+
const int result = open_log_file(log_filename);
605742

606-
sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
607-
now.tm_year + 1900,
608-
now.tm_mon + 1,
609-
now.tm_mday,
610-
now.tm_hour,
611-
now.tm_min,
612-
now.tm_sec);
613-
614-
if (silent != SILENT_ON)
615-
fprintf(stderr, "Warning: Console output active while logging!\n");
616-
617-
fprintf(stderr, "Enabling Logfile '%s'\n", fname);
618-
619-
logfile = fopen(fname, "w");
620-
if (!logfile) {
621-
perror("logfile");
743+
if (result != 0)
622744
return 1;
623-
}
624745
}
625746

626747
/* these settings are static and can be held out of the hot path */
@@ -631,10 +752,20 @@ int main(int argc, char **argv)
631752
msg.msg_control = &ctrlmsg;
632753

633754
while (running) {
634-
635755
if ((num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms)) <= 0) {
636756
//perror("epoll_wait");
637-
running = 0;
757+
if(num_events == -1) {
758+
const int serr = errno;
759+
if (serr == EINTR) {
760+
if (flag_reopen_file == 1) {
761+
if (reopen_file(logfile) != 0) {
762+
return -1;
763+
}
764+
}
765+
} else {
766+
running = 0;
767+
}
768+
}
638769
continue;
639770
}
640771

@@ -817,6 +948,12 @@ int main(int argc, char **argv)
817948
out_fflush:
818949
fflush(stdout);
819950
}
951+
952+
if (flag_reopen_file == 1) {
953+
if(reopen_file(logfile) != 0) {
954+
return -1;
955+
}
956+
}
820957
}
821958

822959
for (i = 0; i < currmax; i++)

0 commit comments

Comments
 (0)