diff options
| -rw-r--r-- | 85-usbmuxd.rules | 4 | ||||
| -rw-r--r-- | main.c | 213 |
2 files changed, 190 insertions, 27 deletions
diff --git a/85-usbmuxd.rules b/85-usbmuxd.rules index 90d49ea..69ddef8 100644 --- a/85-usbmuxd.rules +++ b/85-usbmuxd.rules | |||
| @@ -30,8 +30,8 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbm | |||
| 30 | ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" | 30 | ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" |
| 31 | 31 | ||
| 32 | # Start and stop 'usbmuxd' as required. | 32 | # Start and stop 'usbmuxd' as required. |
| 33 | ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --background --make-pidfile --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" | 33 | ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec /usr/local/sbin/usbmuxd" |
| 34 | ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" | 34 | ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec /usr/local/sbin/usbmuxd" |
| 35 | 35 | ||
| 36 | # skip | 36 | # skip |
| 37 | LABEL="usbmuxd_rules_end" | 37 | LABEL="usbmuxd_rules_end" |
| @@ -24,6 +24,10 @@ | |||
| 24 | #include <errno.h> | 24 | #include <errno.h> |
| 25 | #include <stdlib.h> | 25 | #include <stdlib.h> |
| 26 | #include <string.h> | 26 | #include <string.h> |
| 27 | #include <getopt.h> | ||
| 28 | #include <stdarg.h> | ||
| 29 | #include <syslog.h> | ||
| 30 | #include <fcntl.h> | ||
| 27 | #include <sys/socket.h> | 31 | #include <sys/socket.h> |
| 28 | #include <sys/un.h> | 32 | #include <sys/un.h> |
| 29 | #include <sys/stat.h> | 33 | #include <sys/stat.h> |
| @@ -43,9 +47,12 @@ | |||
| 43 | #define DEFAULT_CHILDREN_CAPACITY 10 | 47 | #define DEFAULT_CHILDREN_CAPACITY 10 |
| 44 | #define DEBUG_LEVEL 0 | 48 | #define DEBUG_LEVEL 0 |
| 45 | 49 | ||
| 50 | #define LOCKFILE "/var/run/usbmuxd.lock" | ||
| 51 | |||
| 46 | static int quit_flag = 0; | 52 | static int quit_flag = 0; |
| 47 | static int fsock = -1; | 53 | static int fsock = -1; |
| 48 | static int verbose = DEBUG_LEVEL; | 54 | static int verbose = DEBUG_LEVEL; |
| 55 | static int foreground = 0; | ||
| 49 | 56 | ||
| 50 | struct device_use_info { | 57 | struct device_use_info { |
| 51 | uint32_t device_id; | 58 | uint32_t device_id; |
| @@ -764,7 +771,43 @@ leave: | |||
| 764 | */ | 771 | */ |
| 765 | static int daemonize() | 772 | static int daemonize() |
| 766 | { | 773 | { |
| 767 | // TODO still to be implemented, also logging is missing! | 774 | pid_t pid; |
| 775 | pid_t sid; | ||
| 776 | |||
| 777 | // already a daemon | ||
| 778 | if (getppid() == 1) return 0; | ||
| 779 | |||
| 780 | pid = fork(); | ||
| 781 | if (pid < 0) { | ||
| 782 | exit(EXIT_FAILURE); | ||
| 783 | } | ||
| 784 | |||
| 785 | if (pid > 0) { | ||
| 786 | // exit parent process | ||
| 787 | exit(EXIT_SUCCESS); | ||
| 788 | } | ||
| 789 | |||
| 790 | // At this point we are executing as the child process | ||
| 791 | |||
| 792 | // Change the file mode mask | ||
| 793 | umask(0); | ||
| 794 | |||
| 795 | // Create a new SID for the child process | ||
| 796 | sid = setsid(); | ||
| 797 | if (sid < 0) { | ||
| 798 | return -1; | ||
| 799 | } | ||
| 800 | |||
| 801 | // Change the current working directory. | ||
| 802 | if ((chdir("/")) < 0) { | ||
| 803 | return -2; | ||
| 804 | } | ||
| 805 | |||
| 806 | // Redirect standard files to /dev/null | ||
| 807 | freopen("/dev/null", "r", stdin); | ||
| 808 | freopen("/dev/null", "w", stdout); | ||
| 809 | freopen("/dev/null", "w", stderr); | ||
| 810 | |||
| 768 | return 0; | 811 | return 0; |
| 769 | } | 812 | } |
| 770 | 813 | ||
| @@ -779,12 +822,85 @@ static void clean_exit(int sig) | |||
| 779 | quit_flag = 1; | 822 | quit_flag = 1; |
| 780 | } | 823 | } |
| 781 | 824 | ||
| 825 | static void logmsg(int prio, char *format, ...) | ||
| 826 | { | ||
| 827 | va_list args; | ||
| 828 | va_start(args, format); | ||
| 829 | |||
| 830 | if (!foreground) { | ||
| 831 | // daemon. log using syslog. | ||
| 832 | vsyslog(prio, format, args); | ||
| 833 | } else { | ||
| 834 | // running in foreground. log to stdout/stderr. | ||
| 835 | char msgbuf[256]; | ||
| 836 | FILE *lfp = stdout; | ||
| 837 | switch(prio) { | ||
| 838 | case LOG_EMERG: | ||
| 839 | case LOG_ALERT: | ||
| 840 | case LOG_CRIT: | ||
| 841 | case LOG_ERR: | ||
| 842 | case LOG_WARNING: | ||
| 843 | lfp = stderr; | ||
| 844 | break; | ||
| 845 | default: | ||
| 846 | lfp = stdout; | ||
| 847 | } | ||
| 848 | strcpy(msgbuf, "usbmuxd: "); | ||
| 849 | vsnprintf(msgbuf+9, 244, format, args); | ||
| 850 | strcat(msgbuf, "\n"); | ||
| 851 | fputs(msgbuf, lfp); | ||
| 852 | } | ||
| 853 | |||
| 854 | va_end(args); | ||
| 855 | } | ||
| 856 | |||
| 857 | static void usage() | ||
| 858 | { | ||
| 859 | printf("usage: usbmuxd [options]\n"); | ||
| 860 | printf("\t-h|--help print this message.\n"); | ||
| 861 | printf("\t-v|--verbose be verbose\n"); | ||
| 862 | printf("\t-f|--foreground do not daemonize\n"); | ||
| 863 | printf("\n"); | ||
| 864 | } | ||
| 865 | |||
| 866 | static void parse_opts(int argc, char **argv) | ||
| 867 | { | ||
| 868 | static struct option longopts[] = { | ||
| 869 | { "help", 0, NULL, 'h' }, | ||
| 870 | { "foreground", 0, NULL, 'f' }, | ||
| 871 | { "verbose", 0, NULL, 'v' }, | ||
| 872 | { NULL, 0, NULL, 0} | ||
| 873 | }; | ||
| 874 | int c; | ||
| 875 | |||
| 876 | while (1) { | ||
| 877 | c = getopt_long(argc, argv, "hfv", longopts, (int *) 0); | ||
| 878 | if (c == -1) { | ||
| 879 | break; | ||
| 880 | } | ||
| 881 | |||
| 882 | switch (c) { | ||
| 883 | case 'h': | ||
| 884 | usage(); | ||
| 885 | exit(0); | ||
| 886 | case 'f': | ||
| 887 | foreground = 1; | ||
| 888 | break; | ||
| 889 | case 'v': | ||
| 890 | sock_stuff_set_verbose(++verbose); | ||
| 891 | break; | ||
| 892 | default: | ||
| 893 | usage(); | ||
| 894 | exit(2); | ||
| 895 | } | ||
| 896 | } | ||
| 897 | } | ||
| 898 | |||
| 782 | /** | 899 | /** |
| 783 | * main function. Initializes all stuff and then loops waiting in accept. | 900 | * main function. Initializes all stuff and then loops waiting in accept. |
| 784 | */ | 901 | */ |
| 785 | int main(int argc, char **argv) | 902 | int main(int argc, char **argv) |
| 786 | { | 903 | { |
| 787 | int foreground = 1; | ||
| 788 | struct sockaddr_un c_addr; | 904 | struct sockaddr_un c_addr; |
| 789 | socklen_t len = sizeof(struct sockaddr_un); | 905 | socklen_t len = sizeof(struct sockaddr_un); |
| 790 | struct client_data *cdata = NULL; | 906 | struct client_data *cdata = NULL; |
| @@ -793,20 +909,47 @@ int main(int argc, char **argv) | |||
| 793 | int i; | 909 | int i; |
| 794 | int result = 0; | 910 | int result = 0; |
| 795 | int cnt = 0; | 911 | int cnt = 0; |
| 912 | FILE *lfd = NULL; | ||
| 913 | struct flock lock; | ||
| 796 | 914 | ||
| 797 | for (i = 1; i < argc; i++) { | 915 | parse_opts(argc, argv); |
| 798 | if (argv[i] != NULL && (!strncmp("-v", argv[i], 2) || !strncmp("--verbose", argv[i], 10))) { | 916 | |
| 799 | sock_stuff_set_verbose(++verbose); | 917 | argc -= optind; |
| 800 | } | 918 | argv += optind; |
| 919 | |||
| 920 | if (!foreground) { | ||
| 921 | openlog("usbmuxd", LOG_PID, 0); | ||
| 801 | } | 922 | } |
| 802 | 923 | ||
| 803 | if (verbose >= 2) fprintf(stderr, "usbmuxd: starting\n"); | 924 | if (verbose >= 2) logmsg(LOG_NOTICE, "starting"); |
| 804 | 925 | ||
| 805 | // TODO: Parameter checking. | 926 | // signal(SIGHUP, reload_conf); // none yet |
| 927 | signal(SIGINT, clean_exit); | ||
| 928 | signal(SIGQUIT, clean_exit); | ||
| 929 | signal(SIGTERM, clean_exit); | ||
| 930 | signal(SIGPIPE, SIG_IGN); | ||
| 931 | |||
| 932 | // check for other running instance | ||
| 933 | lfd = fopen(LOCKFILE, "r"); | ||
| 934 | if (lfd) { | ||
| 935 | lock.l_type = 0; | ||
| 936 | lock.l_whence = SEEK_SET; | ||
| 937 | lock.l_start = 0; | ||
| 938 | lock.l_len = 0; | ||
| 939 | fcntl(fileno(lfd), F_GETLK, &lock); | ||
| 940 | fclose(lfd); | ||
| 941 | if (lock.l_type != F_UNLCK) { | ||
| 942 | logmsg(LOG_NOTICE, "another instance is already running. exiting."); | ||
| 943 | return -1; | ||
| 944 | } | ||
| 945 | } | ||
| 806 | 946 | ||
| 807 | fsock = create_unix_socket(USBMUXD_SOCKET_FILE); | 947 | fsock = create_unix_socket(USBMUXD_SOCKET_FILE); |
| 808 | if (fsock < 0) { | 948 | if (fsock < 0) { |
| 809 | if (verbose >= 1) fprintf(stderr, "Could not create socket, exiting\n"); | 949 | logmsg(LOG_ERR, "Could not create socket, exiting"); |
| 950 | if (!foreground) { | ||
| 951 | closelog(); | ||
| 952 | } | ||
| 810 | return -1; | 953 | return -1; |
| 811 | } | 954 | } |
| 812 | 955 | ||
| @@ -814,26 +957,36 @@ int main(int argc, char **argv) | |||
| 814 | 957 | ||
| 815 | if (!foreground) { | 958 | if (!foreground) { |
| 816 | if (daemonize() < 0) { | 959 | if (daemonize() < 0) { |
| 960 | fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); | ||
| 961 | syslog(LOG_ERR, "FATAL: Could not daemonize!"); | ||
| 962 | closelog(); | ||
| 817 | exit(EXIT_FAILURE); | 963 | exit(EXIT_FAILURE); |
| 818 | } | 964 | } |
| 819 | } | 965 | } |
| 820 | 966 | ||
| 821 | // signal(SIGHUP, reload_conf); // none yet | 967 | // now open the lockfile and place the lock |
| 822 | signal(SIGINT, clean_exit); | 968 | lfd = fopen(LOCKFILE, "w"); |
| 823 | signal(SIGQUIT, clean_exit); | 969 | if (lfd) { |
| 824 | signal(SIGTERM, clean_exit); | 970 | lock.l_type = F_WRLCK; |
| 825 | signal(SIGPIPE, SIG_IGN); | 971 | lock.l_whence = SEEK_SET; |
| 972 | lock.l_start = 0; | ||
| 973 | lock.l_len = 0; | ||
| 974 | fcntl(fileno(lfd), F_SETLK, &lock); | ||
| 975 | } | ||
| 826 | 976 | ||
| 827 | // Reserve space for 10 clients which should be enough. If not, the | 977 | // Reserve space for 10 clients which should be enough. If not, the |
| 828 | // buffer gets enlarged later. | 978 | // buffer gets enlarged later. |
| 829 | children = (struct client_data**)malloc(sizeof(struct client_data*) * children_capacity); | 979 | children = (struct client_data**)malloc(sizeof(struct client_data*) * children_capacity); |
| 830 | if (!children) { | 980 | if (!children) { |
| 831 | if (verbose >= 2) fprintf(stderr, "usbmuxd: Out of memory when allocating memory for child threads. Terminating.\n"); | 981 | logmsg(LOG_ERR, "Out of memory when allocating memory for child threads. Terminating."); |
| 982 | if (!foreground) { | ||
| 983 | closelog(); | ||
| 984 | } | ||
| 832 | exit(EXIT_FAILURE); | 985 | exit(EXIT_FAILURE); |
| 833 | } | 986 | } |
| 834 | memset(children, 0, sizeof(struct client_data*) * children_capacity); | 987 | memset(children, 0, sizeof(struct client_data*) * children_capacity); |
| 835 | 988 | ||
| 836 | if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for connection\n"); | 989 | if (verbose >= 2) logmsg(LOG_NOTICE, "waiting for connection"); |
| 837 | while (!quit_flag) { | 990 | while (!quit_flag) { |
| 838 | // Check the file descriptor before accepting a connection. | 991 | // Check the file descriptor before accepting a connection. |
| 839 | // If no connection attempt is made, just repeat... | 992 | // If no connection attempt is made, just repeat... |
| @@ -845,7 +998,7 @@ int main(int argc, char **argv) | |||
| 845 | if (children[i]) { | 998 | if (children[i]) { |
| 846 | if (children[i]->dead != 0) { | 999 | if (children[i]->dead != 0) { |
| 847 | pthread_join(children[i]->thread, NULL); | 1000 | pthread_join(children[i]->thread, NULL); |
| 848 | if (verbose >= 3) fprintf(stderr, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); | 1001 | if (verbose >= 3) logmsg(LOG_NOTICE, "reclaimed client thread (fd=%d)", children[i]->socket); |
| 849 | free(children[i]); | 1002 | free(children[i]); |
| 850 | children[i] = NULL; | 1003 | children[i] = NULL; |
| 851 | cnt++; | 1004 | cnt++; |
| @@ -864,7 +1017,7 @@ int main(int argc, char **argv) | |||
| 864 | } | 1017 | } |
| 865 | continue; | 1018 | continue; |
| 866 | } else { | 1019 | } else { |
| 867 | if (verbose >= 3) fprintf(stderr, "usbmuxd: select error: %s\n", strerror(errno)); | 1020 | if (verbose >= 3) logmsg(LOG_ERR, "usbmuxd: select error: %s", strerror(errno)); |
| 868 | continue; | 1021 | continue; |
| 869 | } | 1022 | } |
| 870 | } | 1023 | } |
| @@ -873,7 +1026,7 @@ int main(int argc, char **argv) | |||
| 873 | memset(cdata, 0, sizeof(struct client_data)); | 1026 | memset(cdata, 0, sizeof(struct client_data)); |
| 874 | if (!cdata) { | 1027 | if (!cdata) { |
| 875 | quit_flag = 1; | 1028 | quit_flag = 1; |
| 876 | if (verbose >= 1) fprintf(stderr, "usbmuxd: Error: Out of memory! Terminating.\n"); | 1029 | logmsg(LOG_ERR, "Error: Out of memory! Terminating."); |
| 877 | break; | 1030 | break; |
| 878 | } | 1031 | } |
| 879 | 1032 | ||
| @@ -883,12 +1036,12 @@ int main(int argc, char **argv) | |||
| 883 | if (errno == EINTR) { | 1036 | if (errno == EINTR) { |
| 884 | continue; | 1037 | continue; |
| 885 | } else { | 1038 | } else { |
| 886 | if (verbose >= 3) fprintf(stderr, "usbmuxd: Error in accept: %s\n", strerror(errno)); | 1039 | if (verbose >= 3) logmsg(LOG_ERR, "Error in accept: %s", strerror(errno)); |
| 887 | continue; | 1040 | continue; |
| 888 | } | 1041 | } |
| 889 | } | 1042 | } |
| 890 | 1043 | ||
| 891 | if (verbose >= 1) fprintf(stderr, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); | 1044 | if (verbose >= 1) logmsg(LOG_NOTICE, "new client connected (fd=%d)", cdata->socket); |
| 892 | 1045 | ||
| 893 | // create client thread: | 1046 | // create client thread: |
| 894 | if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) { | 1047 | if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) { |
| @@ -900,19 +1053,19 @@ int main(int argc, char **argv) | |||
| 900 | children_capacity++; | 1053 | children_capacity++; |
| 901 | children = realloc(children, sizeof(struct client_data*) * children_capacity); | 1054 | children = realloc(children, sizeof(struct client_data*) * children_capacity); |
| 902 | if (!children) { | 1055 | if (!children) { |
| 903 | if (verbose >= 1) fprintf(stderr, "usbmuxd: Out of memory when enlarging child thread buffer\n"); | 1056 | logmsg(LOG_ERR, "Out of memory when enlarging child thread buffer"); |
| 904 | } | 1057 | } |
| 905 | } | 1058 | } |
| 906 | children[i] = cdata; | 1059 | children[i] = cdata; |
| 907 | } else { | 1060 | } else { |
| 908 | if (verbose >= 3) fprintf(stderr, "usbmuxd: Failed to create client_init_thread.\n"); | 1061 | logmsg(LOG_ERR, "Failed to create client_init_thread."); |
| 909 | close(cdata->socket); | 1062 | close(cdata->socket); |
| 910 | free(cdata); | 1063 | free(cdata); |
| 911 | cdata = NULL; | 1064 | cdata = NULL; |
| 912 | } | 1065 | } |
| 913 | } | 1066 | } |
| 914 | 1067 | ||
| 915 | if (verbose >= 3) fprintf(stderr, "usbmuxd: terminating\n"); | 1068 | if (verbose >= 3) logmsg(LOG_NOTICE, "terminating"); |
| 916 | 1069 | ||
| 917 | // preparing for shutdown: wait for child threads to terminate (if any) | 1070 | // preparing for shutdown: wait for child threads to terminate (if any) |
| 918 | if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); | 1071 | if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); |
| @@ -934,7 +1087,17 @@ int main(int argc, char **argv) | |||
| 934 | 1087 | ||
| 935 | unlink(USBMUXD_SOCKET_FILE); | 1088 | unlink(USBMUXD_SOCKET_FILE); |
| 936 | 1089 | ||
| 937 | if (verbose >= 1) fprintf(stderr, "usbmuxd: terminated\n"); | 1090 | // unlock lock file and close it. |
| 1091 | if (lfd) { | ||
| 1092 | lock.l_type = F_UNLCK; | ||
| 1093 | fcntl(fileno(lfd), F_SETLK, lock); | ||
| 1094 | fclose(lfd); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | if (verbose >= 1) logmsg(LOG_NOTICE, "usbmuxd: terminated"); | ||
| 1098 | if (!foreground) { | ||
| 1099 | closelog(); | ||
| 1100 | } | ||
| 938 | 1101 | ||
| 939 | return 0; | 1102 | return 0; |
| 940 | } | 1103 | } |
