Skip to content

Commit fd7ad60

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 fd7ad60

File tree

1 file changed

+173
-37
lines changed

1 file changed

+173
-37
lines changed

Diff for: candump.c

+173-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,16 @@ static void sigterm(int signo)
171180
running = 0;
172181
}
173182

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

191+
static int idx2dindex(int ifidx, int socket)
192+
{
177193
int i;
178194
struct ifreq ifr;
179195

@@ -221,6 +237,89 @@ static int idx2dindex(int ifidx, int socket)
221237
return i;
222238
}
223239

240+
static int sprint_auto_filename_format(char *buffer)
241+
{
242+
time_t currtime;
243+
struct tm now;
244+
245+
if (time(&currtime) == (time_t)-1) {
246+
perror("time");
247+
return 1;
248+
}
249+
250+
localtime_r(&currtime, &now);
251+
252+
sprintf(buffer, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
253+
now.tm_year + 1900,
254+
now.tm_mon + 1,
255+
now.tm_mday,
256+
now.tm_hour,
257+
now.tm_min,
258+
now.tm_sec);
259+
260+
fprintf(stderr, "Enabling Logfile '%s'\n", buffer);
261+
262+
return 0;
263+
}
264+
265+
/* opens file using global var logfile */
266+
static int open_log_file(const char *file_name)
267+
{
268+
if (silent != SILENT_ON)
269+
fprintf(stderr, "Warning: Console output active while logging!\n");
270+
271+
logfile = fopen(file_name, "w");
272+
273+
if (!logfile) {
274+
perror("logfile");
275+
return 1;
276+
}
277+
278+
return 0;
279+
}
280+
281+
static int reopen_file(FILE *file_handle)
282+
{
283+
const char *fopen_opts = (sighup_count > 0 && !is_auto_log_name) ? "a" : "w";
284+
285+
if (!file_handle)
286+
return 1;
287+
288+
if (is_auto_log_name == 1) {
289+
const int errcode = sprint_auto_filename_format(log_filename);
290+
291+
if (errcode != 0) {
292+
return 1;
293+
}
294+
}
295+
296+
/* close existing filehandle, and open new one if necessary */
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,32 @@ 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_empty_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+
sighup_action.sa_mask = sig_block_mask;
367+
sigemptyset(&sig_empty_mask);
368+
sigterm_action.sa_mask = sig_empty_mask;
369+
370+
sigaction (SIGHUP, &sigterm_action, NULL);
371+
sigaction (SIGINT, &sigterm_action, NULL);
265372

266373
last_tv.tv_sec = 0;
267374
last_tv.tv_usec = 0;
268375

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

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

318452
case 'l':
319453
log = 1;
454+
455+
if (process_logname_arg(optarg) != 0) {
456+
is_auto_log_name = 0;
457+
print_usage(basename(argv[0]));
458+
exit(1);
459+
}
460+
320461
break;
321462

322463
case 'D':
@@ -371,6 +512,10 @@ int main(int argc, char **argv)
371512
exit(0);
372513
}
373514

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

594739
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);
740+
const int result = open_log_file(log_filename);
605741

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");
742+
if (result != 0)
622743
return 1;
623-
}
624744
}
625745

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

633753
while (running) {
634-
635754
if ((num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms)) <= 0) {
636755
//perror("epoll_wait");
637-
running = 0;
756+
if(num_events == -1) {
757+
const int serr = errno;
758+
if (serr == EINTR) {
759+
if (log && flag_reopen_file) {
760+
if (reopen_file(logfile) != 0) {
761+
return -1;
762+
}
763+
}
764+
} else {
765+
running = 0;
766+
}
767+
}
638768
continue;
639769
}
640770

@@ -817,6 +947,12 @@ int main(int argc, char **argv)
817947
out_fflush:
818948
fflush(stdout);
819949
}
950+
951+
if (log && flag_reopen_file == 1) {
952+
if (reopen_file(logfile) != 0) {
953+
return -1;
954+
}
955+
}
820956
}
821957

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

0 commit comments

Comments
 (0)