int main(int argc, char *argv[]) { int listenfd; int res = 0; int lfd; struct flock lock; char pids[10]; parse_opts(argc, argv); argc -= optind; argv += optind; if (!foreground) { verbose += LL_WARNING; log_enable_syslog(); } else { verbose += LL_NOTICE; } /* set log level to specified verbosity */ log_level = verbose; usbmuxd_log(LL_NOTICE, "usbmuxd v%s starting up", PACKAGE_VERSION); should_exit = 0; should_discover = 0; set_signal_handlers(); signal(SIGPIPE, SIG_IGN); res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644); if(res == -1) { usbmuxd_log(LL_FATAL, "Could not open lockfile"); goto terminate; } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; lock.l_pid = 0; fcntl(lfd, F_GETLK, &lock); close(lfd); if (lock.l_type != F_UNLCK) { if (opt_exit) { if (lock.l_pid && !kill(lock.l_pid, 0)) { usbmuxd_log(LL_NOTICE, "Sending signal %d to instance with pid %d", exit_signal, lock.l_pid); res = 0; if (kill(lock.l_pid, exit_signal) < 0) { usbmuxd_log(LL_FATAL, "Could not deliver signal %d to pid %d", exit_signal, lock.l_pid); res = -1; } goto terminate; } else { usbmuxd_log(LL_ERROR, "Could not determine pid of the other running instance!"); res = -1; goto terminate; } } else { if (!opt_disable_hotplug) { usbmuxd_log(LL_ERROR, "Another instance is already running (pid %d). exiting.", lock.l_pid); res = -1; } else { usbmuxd_log(LL_NOTICE, "Another instance is already running (pid %d). Telling it to check for devices.", lock.l_pid); if (lock.l_pid && !kill(lock.l_pid, 0)) { usbmuxd_log(LL_NOTICE, "Sending signal SIGUSR2 to instance with pid %d", lock.l_pid); res = 0; if (kill(lock.l_pid, SIGUSR2) < 0) { usbmuxd_log(LL_FATAL, "Could not deliver SIGUSR2 to pid %d", lock.l_pid); res = -1; } } else { usbmuxd_log(LL_ERROR, "Could not determine pid of the other running instance!"); res = -1; } } goto terminate; } } unlink(lockfile); if (opt_exit) { usbmuxd_log(LL_NOTICE, "No running instance found, none killed. Exiting."); goto terminate; } if (!foreground) { if ((res = daemonize()) < 0) { fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); usbmuxd_log(LL_FATAL, "Could not daemonize!"); goto terminate; } } // now open the lockfile and place the lock res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644); if(res < 0) { usbmuxd_log(LL_FATAL, "Could not open lockfile"); goto terminate; } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) { usbmuxd_log(LL_FATAL, "Lockfile locking failed!"); goto terminate; } sprintf(pids, "%d", getpid()); if ((size_t)(res = write(lfd, pids, strlen(pids))) != strlen(pids)) { usbmuxd_log(LL_FATAL, "Could not write pidfile!"); if(res >= 0) res = -2; goto terminate; } // set number of file descriptors to higher value struct rlimit rlim; getrlimit(RLIMIT_NOFILE, &rlim); rlim.rlim_max = 65536; setrlimit(RLIMIT_NOFILE, (const struct rlimit*)&rlim); usbmuxd_log(LL_INFO, "Creating socket"); res = listenfd = create_socket(); if(listenfd < 0) goto terminate; #ifdef HAVE_LIBIMOBILEDEVICE const char* userprefdir = config_get_config_dir(); struct stat fst; memset(&fst, '\0', sizeof(struct stat)); if (stat(userprefdir, &fst) < 0) { if (mkdir(userprefdir, 0775) < 0) { usbmuxd_log(LL_FATAL, "Failed to create required directory '%s': %s", userprefdir, strerror(errno)); res = -1; goto terminate; } if (stat(userprefdir, &fst) < 0) { usbmuxd_log(LL_FATAL, "stat() failed after creating directory '%s': %s", userprefdir, strerror(errno)); res = -1; goto terminate; } } // make sure permission bits are set correctly if (fst.st_mode != 02775) { if (chmod(userprefdir, 02775) < 0) { usbmuxd_log(LL_WARNING, "chmod(%s, 02775) failed: %s", userprefdir, strerror(errno)); } } #endif // drop elevated privileges if (drop_privileges && (getuid() == 0 || geteuid() == 0)) { struct passwd *pw; if (!drop_user) { usbmuxd_log(LL_FATAL, "No user to drop privileges to?"); res = -1; goto terminate; } pw = getpwnam(drop_user); if (!pw) { usbmuxd_log(LL_FATAL, "Dropping privileges failed, check if user '%s' exists!", drop_user); res = -1; goto terminate; } if (pw->pw_uid == 0) { usbmuxd_log(LL_INFO, "Not dropping privileges to root"); } else { #ifdef HAVE_LIBIMOBILEDEVICE /* make sure the non-privileged user has proper access to the config directory */ if ((fst.st_uid != pw->pw_uid) || (fst.st_gid != pw->pw_gid)) { if (chown(userprefdir, pw->pw_uid, pw->pw_gid) < 0) { usbmuxd_log(LL_WARNING, "chown(%s, %d, %d) failed: %s", userprefdir, pw->pw_uid, pw->pw_gid, strerror(errno)); } } #endif if ((res = initgroups(drop_user, pw->pw_gid)) < 0) { usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set supplementary groups)"); goto terminate; } if ((res = setgid(pw->pw_gid)) < 0) { usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set group ID to %d)", pw->pw_gid); goto terminate; } if ((res = setuid(pw->pw_uid)) < 0) { usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set user ID to %d)", pw->pw_uid); goto terminate; } // security check if (setuid(0) != -1) { usbmuxd_log(LL_FATAL, "Failed to drop privileges properly!"); res = -1; goto terminate; } if (getuid() != pw->pw_uid || getgid() != pw->pw_gid) { usbmuxd_log(LL_FATAL, "Failed to drop privileges properly!"); res = -1; goto terminate; } usbmuxd_log(LL_NOTICE, "Successfully dropped privileges to '%s'", drop_user); } } client_init(); device_init(); usbmuxd_log(LL_INFO, "Initializing USB"); if((res = usb_init()) < 0) goto terminate; usbmuxd_log(LL_INFO, "%d device%s detected", res, (res==1)?"":"s"); usbmuxd_log(LL_NOTICE, "Initialization complete"); if (report_to_parent) if((res = notify_parent(0)) < 0) goto terminate; if(opt_disable_hotplug) { usbmuxd_log(LL_NOTICE, "Automatic device discovery on hotplug disabled."); usb_autodiscover(0); // discovery to be triggered by new instance } if (opt_enable_exit) { usbmuxd_log(LL_NOTICE, "Enabled exit on SIGUSR1 if no devices are attached. Start a new instance with \"--exit\" to trigger."); } res = main_loop(listenfd); if(res < 0) usbmuxd_log(LL_FATAL, "main_loop failed"); usbmuxd_log(LL_NOTICE, "usbmuxd shutting down"); device_kill_connections(); usb_shutdown(); device_shutdown(); client_shutdown(); usbmuxd_log(LL_NOTICE, "Shutdown complete"); terminate: log_disable_syslog(); if (res < 0) res = -res; else res = 0; if (report_to_parent) notify_parent(res); return res; }
int main(int argc, char *argv[]) { int sd = -1; char *conf_file = NULL; struct mosquitto *mosq; struct module *md; struct device *dev; int rc; int i; if (!quiet) printf("Version: %s\n", version); signal(SIGINT, handle_signal); signal(SIGTERM, handle_signal); signal(SIGUSR1, handle_signal); signal(SIGUSR2, handle_signal); signal(SIGALRM, each_sec); for (i=1; i<argc; i++) { if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")){ if(i==argc-1){ fprintf(stderr, "Error: -c argument given but no file specified.\n\n"); print_usage(argv[0]); return 1; }else{ conf_file = argv[i+1]; } i++; }else if(!strcmp(argv[i], "--quiet")){ quiet = true; }else{ fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); print_usage(argv[0]); return 1; } } if(!conf_file) { fprintf(stderr, "Error: No config file given.\n"); return 1; } memset(&config, 0, sizeof(struct bridge_config)); if(config_parse(conf_file, &config)) return 1; if (quiet) config.debug = 0; if (config.debug != 0) printf("Debug: %d\n", config.debug); if (!device_isValid_id(config.id)) { fprintf(stderr, "Invalid id.\n"); return -1; } if (device_init(&bridge, config.id) == -1) return 1; mosquitto_lib_init(); mosq = mosquitto_new(config.id, true, NULL); if(!mosq){ fprintf(stderr, "Error creating mqtt instance.\n"); switch(errno){ case ENOMEM: fprintf(stderr, " out of memory.\n"); break; case EINVAL: fprintf(stderr, " invalid id.\n"); break; } return 1; } snprintf(gbuf, GBUF_SIZE, "%d", PROTO_ST_TIMEOUT); mosquitto_will_set(mosq, bridge.status_topic, strlen(gbuf), gbuf, config.mqtt_qos, MQTT_RETAIN); mosquitto_connect_callback_set(mosq, on_mqtt_connect); mosquitto_disconnect_callback_set(mosq, on_mqtt_disconnect); mosquitto_message_callback_set(mosq, on_mqtt_message); mosquitto_user_data_set(mosq, &sd); if (config.debug > 1) printf("Subscribe topic: %s\n", bridge.config_topic); rc = device_add_module(&bridge, MODULE_MQTT_ID, bridge.id); //TODO: autogen id? if (rc) { fprintf(stderr, "Failed to add mqtt module.\n"); return 1; } if (config.scripts_folder) { if (access(config.scripts_folder, R_OK )) { fprintf(stderr, "Couldn't open scripts folder: %s\n", config.scripts_folder); return 1; } rc = device_add_module(&bridge, MODULE_SCRIPT_ID, bridge.id); //TODO: autogen id? if (rc) { fprintf(stderr, "Failed to add script module.\n"); return 1; } } if (config.interface) { //TODO: check if interface exists if (access("/proc/net/dev", R_OK )) { fprintf(stderr, "Couldn't open /proc/net/dev\n"); return 1; } rc = device_add_module(&bridge, MODULE_BANDWIDTH_ID, bridge.id); //TODO: autogen id? if (rc) { fprintf(stderr, "Failed to add bandwidth module.\n"); return 1; } bandwidth = true; } if (config.serial.port) { sd = serialport_init(config.serial.port, config.serial.baudrate); if( sd == -1 ) { fprintf(stderr, "Couldn't open serial port.\n"); return 1; } else { rc = device_add_module(&bridge, MODULE_SERIAL_ID, bridge.id); //TODO: autogen id? if (rc) { fprintf(stderr, "Failed to add serial module.\n"); return 1; } serialport_flush(sd); bridge.serial_ready = true; if (config.debug) printf("Serial ready.\n"); } } rc = device_add_module(&bridge, MODULE_SIGUSR1_ID, bridge.id); //TODO: autogen id? if (rc) { fprintf(stderr, "Failed to add sigusr1 module.\n"); return 1; } rc = device_add_module(&bridge, MODULE_SIGUSR2_ID, bridge.id); //TODO: autogen id? if (rc) { fprintf(stderr, "Failed to add sigusr2 module.\n"); return 1; } device_print_modules(&bridge); rc = mosquitto_connect(mosq, config.mqtt_host, config.mqtt_port, 60); if (rc) { fprintf(stderr, "Wrong MQTT parameters. Check your config.\n"); return -1; } alarm(1); while (run) { if (bridge.serial_ready) { rc = serial_in(sd, mosq, MODULE_SERIAL_ID); if (rc == -1) { serial_hang(mosq); } else if (rc > 0) { bridge.serial_alive = ALIVE_CNT; } } if (user_signal) { if (config.debug > 1) printf("Signal - SIGUSR: %d\n", user_signal); signal_usr(sd, mosq); } rc = mosquitto_loop(mosq, -1, 1); if (run && rc) { if (config.debug > 2) printf("MQTT loop: %s\n", mosquitto_strerror(rc)); usleep(100000); // wait 100 msec mosquitto_reconnect(mosq); } if (every30s) { every30s = false; bridge.controller = false; for (i = 0; i < bridge.devices_len; i++) { dev = &bridge.devices[i]; if (dev->alive) { dev->alive--; if (!dev->alive) { snprintf(gbuf, GBUF_SIZE, "%d,%s", PROTO_ST_TIMEOUT, dev->id); mqtt_publish(mosq, bridge.status_topic, gbuf); if (dev->md_deps->type == MODULE_MQTT && dev->type == DEVICE_TYPE_NODE) { snprintf(gbuf, GBUF_SIZE, "status/%s", dev->id); rc = mosquitto_unsubscribe(mosq, NULL, gbuf); if (rc) fprintf(stderr, "Error: MQTT unsubscribe returned: %s\n", mosquitto_strerror(rc)); } if (config.debug) printf("Device timeout - id: %s\n", dev->id); } else { if (dev->type == DEVICE_TYPE_CONTROLLER) bridge.controller = true; } } } if (!bridge.controller) bridge.modules_update = false; if (connected) { snprintf(gbuf, GBUF_SIZE, "%d,%d", PROTO_ST_ALIVE, bridge.modules_len); mqtt_publish(mosq, bridge.status_topic, gbuf); if (bridge.modules_update) { snprintf(gbuf, GBUF_SIZE, "%d", PROTO_ST_MODULES_UP); if (mqtt_publish(mosq, bridge.status_topic, gbuf)) bridge.modules_update = false; } if (bandwidth) { md = device_get_module(&bridge, MODULE_BANDWIDTH_ID); if (md) { if (mqtt_publish_bandwidth(mosq, md->topic) == -1) break; } } } else { if (config.debug != 0) printf("MQTT Offline.\n"); } if (bridge.serial_alive) { bridge.serial_alive--; if (!bridge.serial_alive) { if (config.debug > 1) printf("Serial timeout.\n"); serial_hang(mosq); } } else { if (config.serial.port && !bridge.serial_ready) { if (config.debug > 1) printf("Trying to reconnect serial port.\n"); serialport_close(sd); sd = serialport_init(config.serial.port, config.serial.baudrate); if( sd == -1 ) fprintf(stderr, "Couldn't open serial port.\n"); else { serialport_flush(sd); bridge.serial_ready = true; if (config.debug) printf("Serial reopened.\n"); } } } } usleep(20); } if (bridge.serial_ready) { serialport_close(sd); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); config_cleanup(&config); printf("Exiting..\n\n"); return 0; }
static int pcan_usb_plugin(struct usb_interface *interface, const struct usb_device_id *id) { int err; int i, dev_ctrl_count, sizeof_if; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; struct usb_device *usb_dev = interface_to_usbdev(interface); struct pcan_usb_interface *usb_if; int (*device_init)(struct pcan_usb_interface *); DPRINTK(KERN_DEBUG "%s: %s(0x%04x, 0x%04x, 0x%04x)\n", DEVICE_NAME, __func__, usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct, usb_dev->descriptor.bcdDevice); /* check endpoint addresses (numbers) and associated max data length */ /* (only from setting 0) */ /* Since USB-PRO defines also a LIN interface, should reject it when */ /* adapter plugged: make use of endpoint addresses (no other way...) */ iface_desc = &interface->altsetting[0]; DPRINTK(KERN_DEBUG "%s: %s(): bNumEndpoints=%d\n", DEVICE_NAME, __func__, iface_desc->desc.bNumEndpoints); for (i=0; i < iface_desc->desc.bNumEndpoints; i++) { struct usb_endpoint_descriptor *endpoint = &iface_desc->endpoint[i].desc; /* * Below is the list of valid ep addreses. Any other ep address * is considered as not-CAN interface address => no dev createdi */ switch (endpoint->bEndpointAddress) { case 0x01: case 0x81: case 0x02: case 0x82: case 0x03: case 0x83: break; default: #ifdef DEBUG printk(KERN_INFO "%s: %s(): EP address %02x not in CAN range.\n", DEVICE_NAME, __func__, endpoint->bEndpointAddress); printk(KERN_INFO "%s: %s(): ignoring the whole USB interface\n", DEVICE_NAME, __func__); #endif return -ENODEV; } } /* * Does not work with PCAN-USB FD (and 3.14-rc2 ...) * * TODO: check if we could remove this call, because according to * drivers/usb/core/message.c: * * "Instead, the driver [..] may use usb_set_interface() on the * interface it claims" */ if (usb_dev->descriptor.idProduct != PCAN_USBFD_PRODUCT_ID) { /* take the 1st configuration (it's default) */ if ((err = usb_reset_configuration(usb_dev)) < 0) { printk(KERN_ERR "%s: usb_reset_configuration() failed!\n", DEVICE_NAME); return err; } } // only 1 interface is supported // Note: HW_USB_PRO: interface#0 for CAN, #1 for LIN if ((err = usb_set_interface(usb_dev, 0, 0)) < 0) { printk(KERN_ERR "%s: usb_set_interface() failed!\n", DEVICE_NAME); return err; } /* * Now, according to device id, create as many device as CAN * controllers */ switch (usb_dev->descriptor.idProduct) { #ifdef HW_USB_FD case PCAN_USBFD_PRODUCT_ID: dev_ctrl_count = 1; device_init = pcan_usbfd_init; break; #endif #ifdef HW_USB_PRO_FD case PCAN_USBPROFD_PRODUCT_ID: dev_ctrl_count = 2; device_init = pcan_usbfd_init; break; #endif #ifdef HW_USB_PRO case PCAN_USBPRO_PRODUCT_ID: dev_ctrl_count = 2; device_init = pcan_usbpro_init; break; #endif case PCAN_USB_PRODUCT_ID: default: dev_ctrl_count = 1; device_init = pcan_usb_init; break; } printk(KERN_INFO "%s: new ", DEVICE_NAME); if (usb_dev->speed == USB_SPEED_HIGH) printk("high speed "); printk("usb adapter with %u CAN controller(s) detected\n", dev_ctrl_count); /* create our interface object for the USB device */ sizeof_if = sizeof(struct pcan_usb_interface) + \ sizeof(struct pcandev) * (dev_ctrl_count-1); usb_if = (struct pcan_usb_interface *)kmalloc(sizeof_if, GFP_KERNEL); if (!usb_if) { printk(KERN_ERR "%s: kmalloc(%d) failed!\n", DEVICE_NAME, sizeof_if); return err; } memset(usb_if, '\0', sizeof_if); // store pointer to kernel supplied usb_dev usb_if->usb_dev = usb_dev; usb_if->usb_intf = interface; usb_if->dev_ctrl_count = dev_ctrl_count; // preset finish flags atomic_set(&usb_if->cmd_sync_complete, 0); atomic_set(&usb_if->cmd_async_complete, 1); // preset active URB counter atomic_set(&usb_if->active_urbs, 0); init_waitqueue_head(&usb_if->usb_wait_queue); /* get endpoint addresses (numbers) and associated max data length */ /* (only from setting 0) */ #ifdef HW_USB_PRO /* * Function Interface Endpoints DeviceId * --------- --------- ----------------------------------------- * Control 0 * CAN 0 "CAN-Device", * USB\VID_0c72&PID_000d&MI_00 * 1=Command, bidi for both CAN_Ctrller * 2=CAN-Controller 0, rcv (IN) both CAN-Ctrller, * transmit (OUT) CAN-Ctrl#0, * 3=CAN-Controller 1 transmit (OUT) CAN-Ctrl#1 * LIN 1 "LIN-Device", * USB\VID_0c72&PID_000d&MI_01 * 4=Command, * 5=Controller 0, * 6=Controller 1 */ #endif for (i=0; i < iface_desc->desc.bNumEndpoints; i++) { PCAN_ENDPOINT *pipe_addr = NULL; endpoint = &iface_desc->endpoint[i].desc; DPRINTK(KERN_DEBUG "%s: %s(): EP[%d]={addr=%d max=%d}\n", DEVICE_NAME, __func__, i, endpoint->bEndpointAddress, endpoint->wMaxPacketSize); switch (endpoint->bEndpointAddress) { case 0x01: pipe_addr = &usb_if->pipe_cmd_out; break; case 0x81: pipe_addr = &usb_if->pipe_cmd_in; break; case 0x02: switch (usb_dev->descriptor.idProduct) { #ifdef HW_USB_FD case PCAN_USBFD_PRODUCT_ID: #endif #ifdef HW_USB_PRO_FD case PCAN_USBPROFD_PRODUCT_ID: #endif #ifdef HW_USB_PRO case PCAN_USBPRO_PRODUCT_ID: #endif case PCAN_USB_PRODUCT_ID: default: pipe_addr = &usb_if->dev[0].port.usb.pipe_write; break; } break; case 0x82: pipe_addr = &usb_if->pipe_read; break; case 0x03: switch (usb_dev->descriptor.idProduct) { #ifdef HW_USB_FD case PCAN_USBFD_PRODUCT_ID: #endif #ifdef HW_USB_PRO_FD case PCAN_USBPROFD_PRODUCT_ID: #endif #ifdef HW_USB_PRO case PCAN_USBPRO_PRODUCT_ID: #endif pipe_addr = &usb_if->dev[1].port.usb.pipe_write; break; } case 0x83: /* Unused pipe for PCAN-USB-PRO */ /* But seems that need to be reset too... */ /* TBD */ break; default: continue; } if (pipe_addr) { pipe_addr->ucNumber = endpoint->bEndpointAddress; pipe_addr->wDataSz = le16_to_cpu(endpoint->wMaxPacketSize); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) usb_reset_endpoint(usb_dev, endpoint->bEndpointAddress); #endif } /* ucRevision needs to be defined before allocating resources (PCAN-USB) */ #if defined(__LITTLE_ENDIAN) usb_if->ucHardcodedDevNr = (uint8_t)(usb_if->usb_dev->descriptor.bcdDevice & 0xff); usb_if->ucRevision = (uint8_t)(usb_if->usb_dev->descriptor.bcdDevice >> 8); #elif defined(__BIG_ENDIAN) usb_if->ucHardcodedDevNr = (uint8_t)(usb_if->usb_dev->descriptor.bcdDevice >> 8); usb_if->ucRevision = (uint8_t)(usb_if->usb_dev->descriptor.bcdDevice & 0xff); #else #error "Please fix the endianness defines in <asm/byteorder.h>" #endif DPRINTK(KERN_DEBUG "%s(): ucHardcodedDevNr=0x%02x ucRevision=0x%02X\n", __func__, usb_if->ucHardcodedDevNr, usb_if->ucRevision); if ((err = pcan_usb_allocate_resources(usb_if))) goto reject; usb_set_intfdata(interface, usb_if); /* call initialisation callback for entire device */ device_init(usb_if); /* install the reception part for the interface */ if (!atomic_read(&usb_if->read_data.use_count)) { FILL_BULK_URB(&usb_if->read_data, usb_if->usb_dev, usb_rcvbulkpipe(usb_if->usb_dev, usb_if->pipe_read.ucNumber), usb_if->read_buffer_addr[0], usb_if->read_buffer_size, pcan_usb_read_notify, usb_if); // submit urb if ((err = __usb_submit_urb(&usb_if->read_data))) { printk(KERN_ERR "%s: %s() can't submit! (%d)\n", DEVICE_NAME, __func__, err); goto reject; } atomic_inc(&usb_if->active_urbs); } /* next, initialize each controller */ for (i=0; i < usb_if->dev_ctrl_count; i++) { err = pcan_usb_create_dev(usb_if, i); if (err) { for (; i > 0; i--) { // TBD pcan_usb_delete_dev(); } break; } } reject: return err; }
void init(const char* cfg) { device_init(cfg); }