diff --git a/isotptun.c b/isotptun.c index fc2a8d5..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); @@ -154,9 +177,9 @@ 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(0); + exit(EXIT_FAILURE); } break; } @@ -174,9 +197,9 @@ 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(0); + exit(EXIT_FAILURE); } break; } @@ -189,9 +212,9 @@ 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(0); + exit(EXIT_FAILURE); } break; @@ -220,9 +243,9 @@ 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(0); + exit(EXIT_FAILURE); } break; @@ -230,15 +253,19 @@ int main(int argc, char **argv) verbose = 1; break; + case 'D': + run_as_daemon = 1; + break; + 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 +274,18 @@ 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 (!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"); - exit(1); + perror_syslog("socket"); + exit(EXIT_FAILURE); } setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)); @@ -260,33 +293,33 @@ 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); + perror_syslog("link layer sockopt"); + exit(EXIT_FAILURE); } } 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(1); + exit(EXIT_FAILURE); } addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("bind"); + perror_syslog("bind"); close(s); - exit(1); + exit(EXIT_FAILURE); } if ((t = open("/dev/net/tun", O_RDWR)) < 0) { - perror("open tunfd"); + perror_syslog("open tunfd"); close(s); close(t); - exit(1); + exit(EXIT_FAILURE); } memset(&ifr, 0, sizeof(ifr)); @@ -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(1); + 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) @@ -351,5 +397,5 @@ int main(int argc, char **argv) close(s); close(t); - return 0; + return EXIT_SUCCESS; }