From 7eb005d9f33621d1b4b585e6cfb497ae34dff886 Mon Sep 17 00:00:00 2001 From: Marko Kohtala Date: Tue, 14 Feb 2017 11:12:51 +0200 Subject: [PATCH 1/3] isotptun: use EXIT_FAILURE instead of 0 (EXIT_SUCCESS) for errors Exit code does not tell if the service was provided or if it was not provided due to command line or setup errors. Change errors to return EXIT_FAILURE instead of 0. Also change other uses of 0 to EXIT_SUCCESS and 1 to EXIT_FAILURE for clarity and POSIX conformance. Signed-off-by: Marko Kohtala --- isotptun.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/isotptun.c b/isotptun.c index fc2a8d5..e1ed74b 100644 --- a/isotptun.c +++ b/isotptun.c @@ -156,7 +156,7 @@ int main(int argc, char **argv) else { printf("incorrect extended addr values '%s'.\n", optarg); print_usage(basename(argv[0])); - exit(0); + exit(EXIT_FAILURE); } break; } @@ -176,7 +176,7 @@ int main(int argc, char **argv) else { printf("incorrect padding values '%s'.\n", optarg); print_usage(basename(argv[0])); - exit(0); + exit(EXIT_FAILURE); } break; } @@ -191,7 +191,7 @@ int main(int argc, char **argv) else { printf("unknown padding check option '%c'.\n", optarg[0]); print_usage(basename(argv[0])); - exit(0); + exit(EXIT_FAILURE); } break; @@ -222,7 +222,7 @@ int main(int argc, char **argv) &llopts.tx_flags) != 3) { printf("unknown link layer options '%s'.\n", optarg); print_usage(basename(argv[0])); - exit(0); + exit(EXIT_FAILURE); } break; @@ -232,13 +232,13 @@ int main(int argc, char **argv) case '?': print_usage(basename(argv[0])); - exit(0); + exit(EXIT_SUCCESS); break; default: fprintf(stderr, "Unknown option %c\n", opt); print_usage(basename(argv[0])); - exit(1); + exit(EXIT_FAILURE); break; } } @@ -247,12 +247,12 @@ int main(int argc, char **argv) (addr.can_addr.tp.tx_id == NO_CAN_ID) || (addr.can_addr.tp.rx_id == NO_CAN_ID)) { print_usage(basename(argv[0])); - exit(1); + exit(EXIT_FAILURE); } if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) { perror("socket"); - exit(1); + exit(EXIT_FAILURE); } setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)); @@ -261,7 +261,7 @@ int main(int argc, char **argv) if (llopts.tx_dl) { if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) { perror("link layer sockopt"); - exit(1); + exit(EXIT_FAILURE); } } @@ -270,7 +270,7 @@ int main(int argc, char **argv) if (!ifr.ifr_ifindex) { perror("if_nametoindex"); close(s); - exit(1); + exit(EXIT_FAILURE); } addr.can_family = AF_CAN; @@ -279,14 +279,14 @@ int main(int argc, char **argv) if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); close(s); - exit(1); + exit(EXIT_FAILURE); } if ((t = open("/dev/net/tun", O_RDWR)) < 0) { perror("open tunfd"); close(s); close(t); - exit(1); + exit(EXIT_FAILURE); } memset(&ifr, 0, sizeof(ifr)); @@ -298,7 +298,7 @@ int main(int argc, char **argv) perror("ioctl tunfd"); close(s); close(t); - exit(1); + exit(EXIT_FAILURE); } while (running) { @@ -351,5 +351,5 @@ int main(int argc, char **argv) close(s); close(t); - return 0; + return EXIT_SUCCESS; } From 51192feff873b2cf011d955ea9c9dffe4ffbd1c9 Mon Sep 17 00:00:00 2001 From: Marko Kohtala Date: Tue, 14 Feb 2017 11:14:29 +0200 Subject: [PATCH 2/3] isotptun: print command line parsing error messages to stderr Command line parsing error messages are printed to stdout. Other errors and usage goes to stderr. Change to print errors to stderr. Signed-off-by: Marko Kohtala --- isotptun.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/isotptun.c b/isotptun.c index e1ed74b..241a30e 100644 --- a/isotptun.c +++ b/isotptun.c @@ -154,7 +154,7 @@ int main(int argc, char **argv) else if (elements == 2) opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR); else { - printf("incorrect extended addr values '%s'.\n", optarg); + fprintf(stderr, "incorrect extended addr values '%s'.\n", optarg); print_usage(basename(argv[0])); exit(EXIT_FAILURE); } @@ -174,7 +174,7 @@ int main(int argc, char **argv) else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1) opts.flags |= CAN_ISOTP_RX_PADDING; else { - printf("incorrect padding values '%s'.\n", optarg); + fprintf(stderr, "incorrect padding values '%s'.\n", optarg); print_usage(basename(argv[0])); exit(EXIT_FAILURE); } @@ -189,7 +189,7 @@ int main(int argc, char **argv) else if (optarg[0] == 'a') opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA); else { - printf("unknown padding check option '%c'.\n", optarg[0]); + fprintf(stderr, "unknown padding check option '%c'.\n", optarg[0]); print_usage(basename(argv[0])); exit(EXIT_FAILURE); } @@ -220,7 +220,7 @@ int main(int argc, char **argv) &llopts.mtu, &llopts.tx_dl, &llopts.tx_flags) != 3) { - printf("unknown link layer options '%s'.\n", optarg); + fprintf(stderr, "unknown link layer options '%s'.\n", optarg); print_usage(basename(argv[0])); exit(EXIT_FAILURE); } From 35f3dc375b429d815d30c520b37dd8b8d176c0b4 Mon Sep 17 00:00:00 2001 From: Marko Kohtala Date: Tue, 14 Feb 2017 11:16:07 +0200 Subject: [PATCH 3/3] isotptun: add -D option to daemonize after tun device created System startup needs to wait for tun device to be created before continuing on use of the tun device. Add -D option to fork a daemon of isotptun and exit(EXIT_SUCCESS) when the tun device can be used. Log errors to syslog when daemonized or to stderr when in foreground. Signed-off-by: Marko Kohtala --- isotptun.c | 74 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/isotptun.c b/isotptun.c index 241a30e..3b4fe3a 100644 --- a/isotptun.c +++ b/isotptun.c @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include #include @@ -65,6 +67,9 @@ #include #include +/* Change this to whatever your daemon is called */ +#define DAEMON_NAME "isotptun" + #define NO_CAN_ID 0xFFFFFFFFU #define DEFAULT_NAME "ctun%d" @@ -74,6 +79,26 @@ static volatile int running = 1; +static void fake_syslog(int priority, const char *format, ...) +{ + va_list ap; + + fprintf(stderr, "[%d] ", priority); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +typedef void (*syslog_t)(int priority, const char *format, ...); +static syslog_t syslogger = syslog; + +void perror_syslog(const char *s) +{ + const char *colon = s ? ": " : ""; + syslogger(LOG_ERR, "%s%s%s", s, colon, strerror(errno)); +} + void print_usage(char *prg) { fprintf(stderr, "\nUsage: %s [options] \n\n", prg); @@ -90,6 +115,7 @@ void print_usage(char *prg) fprintf(stderr, " -b (blocksize. 0 = off)\n"); fprintf(stderr, " -m (STmin in ms/ns. See spec.)\n"); fprintf(stderr, " -w (max. wait frame transmissions.)\n"); + fprintf(stderr, " -D (daemonize to background when tun device created)\n"); fprintf(stderr, " -h (half duplex mode.)\n"); fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n"); fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n"); @@ -118,14 +144,11 @@ int main(int argc, char **argv) unsigned char buffer[BUF_LEN]; static char name[IFNAMSIZ] = DEFAULT_NAME; int nbytes; - - signal(SIGTERM, sigterm); - signal(SIGHUP, sigterm); - signal(SIGINT, sigterm); + int run_as_daemon = 0; addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID; - while ((opt = getopt(argc, argv, "s:d:n:x:p:P:t:b:m:whL:v?")) != -1) { + while ((opt = getopt(argc, argv, "s:d:n:x:p:P:t:b:m:whL:vD?")) != -1) { switch (opt) { case 's': addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16); @@ -230,6 +253,10 @@ int main(int argc, char **argv) verbose = 1; break; + case 'D': + run_as_daemon = 1; + break; + case '?': print_usage(basename(argv[0])); exit(EXIT_SUCCESS); @@ -250,8 +277,14 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (!run_as_daemon) + syslogger = fake_syslog; + + /* Initialize the logging interface */ + openlog(DAEMON_NAME, LOG_PID, LOG_LOCAL5); + if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) { - perror("socket"); + perror_syslog("socket"); exit(EXIT_FAILURE); } @@ -260,7 +293,7 @@ int main(int argc, char **argv) if (llopts.tx_dl) { if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) { - perror("link layer sockopt"); + perror_syslog("link layer sockopt"); exit(EXIT_FAILURE); } } @@ -268,7 +301,7 @@ int main(int argc, char **argv) strncpy(ifr.ifr_name, argv[optind], IFNAMSIZ); ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); if (!ifr.ifr_ifindex) { - perror("if_nametoindex"); + perror_syslog("if_nametoindex"); close(s); exit(EXIT_FAILURE); } @@ -277,13 +310,13 @@ int main(int argc, char **argv) addr.can_ifindex = ifr.ifr_ifindex; if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("bind"); + perror_syslog("bind"); close(s); exit(EXIT_FAILURE); } if ((t = open("/dev/net/tun", O_RDWR)) < 0) { - perror("open tunfd"); + perror_syslog("open tunfd"); close(s); close(t); exit(EXIT_FAILURE); @@ -295,12 +328,25 @@ int main(int argc, char **argv) ifr.ifr_name[IFNAMSIZ - 1] = '\0'; if (ioctl(t, TUNSETIFF, (void *) &ifr) < 0) { - perror("ioctl tunfd"); + perror_syslog("ioctl tunfd"); close(s); close(t); exit(EXIT_FAILURE); } + /* Now the tun device exists. We can daemonize to let the + * parent continue and use the network interface. */ + if (run_as_daemon) { + if (daemon(0, 0)) { + syslogger(LOG_ERR, "failed to daemonize"); + exit(EXIT_FAILURE); + } + } + + signal(SIGTERM, sigterm); + signal(SIGHUP, sigterm); + signal(SIGINT, sigterm); + while (running) { FD_ZERO(&rdfs); @@ -308,14 +354,14 @@ int main(int argc, char **argv) FD_SET(t, &rdfs); if ((ret = select(t+1, &rdfs, NULL, NULL, NULL)) < 0) { - perror("select"); + perror_syslog("select"); continue; } if (FD_ISSET(s, &rdfs)) { nbytes = read(s, buffer, BUF_LEN); if (nbytes < 0) { - perror("read isotp socket"); + perror_syslog("read isotp socket"); return -1; } if (nbytes > MAX_PDU_LENGTH) @@ -333,7 +379,7 @@ int main(int argc, char **argv) if (FD_ISSET(t, &rdfs)) { nbytes = read(t, buffer, BUF_LEN); if (nbytes < 0) { - perror("read tunfd"); + perror_syslog("read tunfd"); return -1; } if (nbytes > MAX_PDU_LENGTH)