/*
- * $Id$
- */
-
-/*
* slcand.c - userspace daemon for serial line CAN interface driver SLCAN
*
* Copyright (c) 2009 Robert Haddon <robert.haddon@verari.com>
* A copy of the license is included in the section entitled "GNU
* Free Documentation License".
*
- * Send feedback to <socketcan-users@lists.berlios.de>
+ * Send feedback to <linux-can@vger.kernel.org>
*
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
+#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <net/if.h>
/* default slcan line discipline since Kernel 2.6.25 */
#define LDISC_N_SLCAN 17
/* Change this to the user under which to run */
#define RUN_AS_USER "root"
+/* The length of ttypath buffer */
+#define TTYPATH_LENGTH 64
+
+/* The length of pidfile name buffer */
+#define PIDFILE_LENGTH 64
+
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
void print_usage(char *prg)
{
- fprintf(stderr, "\nUsage: %s tty\n\n", prg);
+ fprintf(stderr, "\nUsage: %s tty [name]\n\n", prg);
fprintf(stderr, "Example:\n");
fprintf(stderr, "%s ttyUSB1\n", prg);
- fprintf(stderr, "%s ttyS0\n", prg);
+ fprintf(stderr, "%s ttyS0 can0\n", prg);
fprintf(stderr, "\n");
exit(EXIT_FAILURE);
}
}
}
-static void daemonize (const char *lockfile, char *tty)
+static void daemonize (const char *lockfile, char *tty, char *name)
{
pid_t pid, sid, parent;
int lfp = -1;
FILE * pFile;
char const *pidprefix = "/var/run/";
char const *pidsuffix = ".pid";
- char *pidfile;
- pidfile = malloc((strlen(pidprefix) +strlen(DAEMON_NAME) + strlen(tty) + strlen(pidsuffix) + 1) * sizeof(char));
- sprintf(pidfile, "%s%s-%s%s", pidprefix, DAEMON_NAME, tty, pidsuffix);
+ char pidfile[PIDFILE_LENGTH];
+
+ snprintf(pidfile, PIDFILE_LENGTH, "%s%s-%s%s", pidprefix, DAEMON_NAME, tty, pidsuffix);
/* already a daemon */
if (getppid () == 1)
struct passwd *pw = getpwnam (RUN_AS_USER);
if (pw)
{
- syslog (LOG_NOTICE, "setting user to " RUN_AS_USER);
+ //syslog (LOG_NOTICE, "setting user to " RUN_AS_USER);
setuid (pw->pw_uid);
}
}
int main (int argc, char *argv[])
{
- char *tty;
- char *ttypath;
+ char *tty = NULL;
+ char ttypath[TTYPATH_LENGTH];
char const *devprefix = "/dev/";
+ char *name = NULL;
+ char buf[IFNAMSIZ+1];
/* Initialize the logging interface */
openlog (DAEMON_NAME, LOG_PID, LOG_LOCAL5);
/* See how we're called */
- if (argc != 2)
+ if (argc == 2) {
+ tty = argv[1];
+ } else if (argc == 3) {
+ tty = argv[1];
+ name = argv[2];
+ if (strlen(name) > IFNAMSIZ-1)
+ print_usage(argv[0]);
+ } else {
print_usage(argv[0]);
- tty = argv[1];
+ }
/* Prepare the tty device name string */
char * pch;
if (pch == tty) {
print_usage(argv[0]);
}
- ttypath = malloc((strlen(devprefix) + strlen(tty)) * sizeof(char));
- sprintf (ttypath, "%s%s", devprefix, tty);
+
+ snprintf (ttypath, TTYPATH_LENGTH, "%s%s", devprefix, tty);
syslog (LOG_INFO, "starting on TTY device %s", ttypath);
/* Daemonize */
- daemonize ("/var/lock/" DAEMON_NAME, tty);
+ daemonize ("/var/lock/" DAEMON_NAME, tty, name);
/* Now we are a daemon -- do the work for which we were paid */
int fd;
int ldisc = LDISC_N_SLCAN;
if ((fd = open (ttypath, O_WRONLY | O_NOCTTY )) < 0) {
+ syslog (LOG_NOTICE, "failed to open TTY device %s\n", ttypath);
perror(ttypath);
exit(1);
}
+ /* set slcan like discipline on given tty */
if (ioctl (fd, TIOCSETD, &ldisc) < 0) {
- perror("ioctl");
+ perror("ioctl TIOCSETD");
exit(1);
}
+
+ /* retrieve the name of the created CAN netdevice */
+ if (ioctl (fd, SIOCGIFNAME, buf) < 0) {
+ perror("ioctl SIOCGIFNAME");
+ exit(1);
+ }
+
+ syslog (LOG_NOTICE, "attached TTY %s to netdevice %s\n", ttypath, buf);
+
+ /* try to rename the created netdevice */
+ if (name) {
+ struct ifreq ifr;
+ int s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ perror("socket for interface rename");
+ else {
+ strncpy (ifr.ifr_name, buf, IFNAMSIZ);
+ strncpy (ifr.ifr_newname, name, IFNAMSIZ);
+
+ if (ioctl(s, SIOCSIFNAME, &ifr) < 0) {
+ syslog (LOG_NOTICE, "netdevice %s rename to %s failed\n", buf, name);
+ perror("ioctl SIOCSIFNAME rename");
+ exit(1);
+ } else
+ syslog (LOG_NOTICE, "netdevice %s renamed to %s\n", buf, name);
+
+ close(s);
+ }
+ }
/* The Big Loop */
while (1) {