| /* |
| * wiringPiD.c: |
| * Copyright (c) 2012-2017 Gordon Henderson |
| *********************************************************************** |
| * This file is part of wiringPi: |
| * https://projects.drogon.net/raspberry-pi/wiringpi/ |
| * |
| * wiringPi is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU Lesser General Public License as published by |
| * the Free Software Foundation, either version 3 of the License, or |
| * (at your option) any later version. |
| * |
| * wiringPi is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public License |
| * along with wiringPi. If not, see <http://www.gnu.org/licenses/>. |
| *********************************************************************** |
| */ |
| |
| #include <arpa/inet.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <syslog.h> |
| #include <signal.h> |
| #include <errno.h> |
| |
| #include <wiringPi.h> |
| #include <wpiExtensions.h> |
| |
| #include "drcNetCmd.h" |
| #include "network.h" |
| #include "runRemote.h" |
| #include "daemonise.h" |
| |
| |
| #define PIDFILE "/var/run/wiringPiD.pid" |
| |
| |
| // Globals |
| |
| static const char *usage = "[-h] [-d] [-g | -1 | -z] [[-x extension:pin:params] ...] password" ; |
| static int doDaemon = FALSE ; |
| |
| // |
| |
| static void logMsg (const char *message, ...) |
| { |
| va_list argp ; |
| char buffer [1024] ; |
| |
| va_start (argp, message) ; |
| vsnprintf (buffer, 1023, message, argp) ; |
| va_end (argp) ; |
| |
| if (doDaemon) |
| syslog (LOG_DAEMON | LOG_INFO, "%s", buffer) ; |
| else |
| printf ("%s\n", buffer) ; |
| } |
| |
| |
| /* |
| * sigHandler: |
| * setupSigHandler: |
| * Somehing has happened that would normally terminate the program so try |
| * to close down nicely. |
| ********************************************************************************* |
| */ |
| |
| void sigHandler (int sig) |
| { |
| logMsg ("Exiting on signal %d: %s", sig, strsignal (sig)) ; |
| (void)unlink (PIDFILE) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| void setupSigHandler (void) |
| { |
| struct sigaction action ; |
| |
| sigemptyset (&action.sa_mask) ; |
| action.sa_flags = 0 ; |
| |
| // Ignore what we can |
| |
| action.sa_handler = SIG_IGN ; |
| |
| sigaction (SIGHUP, &action, NULL) ; |
| sigaction (SIGTTIN, &action, NULL) ; |
| sigaction (SIGTTOU, &action, NULL) ; |
| |
| // Trap what we can to exit gracefully |
| |
| action.sa_handler = sigHandler ; |
| |
| sigaction (SIGINT, &action, NULL) ; |
| sigaction (SIGQUIT, &action, NULL) ; |
| sigaction (SIGILL, &action, NULL) ; |
| sigaction (SIGABRT, &action, NULL) ; |
| sigaction (SIGFPE, &action, NULL) ; |
| sigaction (SIGSEGV, &action, NULL) ; |
| sigaction (SIGPIPE, &action, NULL) ; |
| sigaction (SIGALRM, &action, NULL) ; |
| sigaction (SIGTERM, &action, NULL) ; |
| sigaction (SIGUSR1, &action, NULL) ; |
| sigaction (SIGUSR2, &action, NULL) ; |
| sigaction (SIGCHLD, &action, NULL) ; |
| sigaction (SIGTSTP, &action, NULL) ; |
| sigaction (SIGBUS, &action, NULL) ; |
| } |
| |
| |
| /* |
| * The works... |
| ********************************************************************************* |
| */ |
| |
| int main (int argc, char *argv []) |
| { |
| int clientFd ; |
| char *p, *password ; |
| int i ; |
| int port = DEFAULT_SERVER_PORT ; |
| int wpiSetup = 0 ; |
| |
| if (argc < 2) |
| { |
| fprintf (stderr, "Usage: %s %s\n", argv [0], usage) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| // Help? |
| |
| if (strcasecmp (argv [1], "-h") == 0) |
| { |
| printf ("Usage: %s %s\n", argv [0], usage) ; |
| return 0 ; |
| } |
| |
| // Daemonize? |
| // Must come before the other args as e.g. some extensions |
| // open files which get closed on daemonise... |
| |
| if (strcasecmp (argv [1], "-d") == 0) |
| { |
| if (geteuid () != 0) |
| { |
| fprintf (stderr, "%s: Must be root to run as a daemon.\n", argv [0]) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| doDaemon = TRUE ; |
| daemonise (PIDFILE) ; |
| |
| for (i = 2 ; i < argc ; ++i) |
| argv [i - 1] = argv [i] ; |
| --argc ; |
| } |
| |
| // Scan all other arguments |
| |
| while (*argv [1] == '-') |
| { |
| |
| // Look for wiringPi setup arguments: |
| // Same as the gpio command and rtb. |
| |
| // -g - bcm_gpio |
| |
| if (strcasecmp (argv [1], "-g") == 0) |
| { |
| if (wpiSetup == 0) |
| { |
| logMsg ("BCM_GPIO mode selected") ; |
| wiringPiSetupGpio () ; |
| } |
| |
| for (i = 2 ; i < argc ; ++i) |
| argv [i - 1] = argv [i] ; |
| --argc ; |
| ++wpiSetup ; |
| continue ; |
| } |
| |
| // -1 - physical pins |
| |
| if (strcasecmp (argv [1], "-1") == 0) |
| { |
| if (wpiSetup == 0) |
| { |
| logMsg ("GPIO-PHYS mode selected") ; |
| wiringPiSetupPhys () ; |
| } |
| |
| for (i = 2 ; i < argc ; ++i) |
| argv [i - 1] = argv [i] ; |
| --argc ; |
| ++wpiSetup ; |
| continue ; |
| } |
| |
| // -z - no wiringPi - blocks remotes accessing local pins |
| |
| if (strcasecmp (argv [1], "-z") == 0) |
| { |
| if (wpiSetup == 0) |
| logMsg ("No GPIO mode selected") ; |
| |
| for (i = 2 ; i < argc ; ++i) |
| argv [i - 1] = argv [i] ; |
| --argc ; |
| noLocalPins = TRUE ; |
| ++wpiSetup ; |
| continue ; |
| } |
| |
| // -p to select the port |
| |
| if (strcasecmp (argv [1], "-p") == 0) |
| { |
| if (argc < 3) |
| { |
| logMsg ("-p missing extension port") ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| logMsg ("Setting port to: %s", argv [2]) ; |
| |
| port = atoi (argv [2]) ; |
| if ((port < 1) || (port > 65535)) |
| { |
| logMsg ("Invalid server port: %d", port) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| // Shift args down by 2 |
| |
| for (i = 3 ; i < argc ; ++i) |
| argv [i - 2] = argv [i] ; |
| argc -= 2 ; |
| |
| continue ; |
| } |
| |
| // Check for -x argument to load in a new extension |
| // -x extension:base:args |
| // Can load many modules to extend the daemon. |
| |
| if (strcasecmp (argv [1], "-x") == 0) |
| { |
| if (argc < 3) |
| { |
| logMsg ("-x missing extension name:data:etc.") ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| logMsg ("Loading extension: %s", argv [2]) ; |
| |
| if (!loadWPiExtension (argv [0], argv [2], TRUE)) |
| { |
| logMsg ("Extension load failed: %s", strerror (errno)) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| // Shift args down by 2 |
| |
| for (i = 3 ; i < argc ; ++i) |
| argv [i - 2] = argv [i] ; |
| argc -= 2 ; |
| |
| continue ; |
| } |
| |
| logMsg ("Invalid parameter: %s", argv [1]) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| // Default to wiringPi mode |
| |
| if (wpiSetup == 0) |
| { |
| logMsg ("WiringPi GPIO mode selected") ; |
| wiringPiSetup () ; |
| } |
| |
| // Finally, should just be one arg left - the password... |
| |
| if (argc != 2) |
| { |
| logMsg ("No password supplied") ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| if (strlen (argv [1]) < 6) |
| { |
| logMsg ("Password too short - at least 6 chars, not %d", strlen (argv [1])) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| if ((password = malloc (strlen (argv [1]) + 1)) == NULL) |
| { |
| logMsg ("Out of memory") ; |
| exit (EXIT_FAILURE) ; |
| } |
| strcpy (password, argv [1]) ; |
| |
| // Wipe out the password on the command-line in a vague attempt to try to |
| // hide it from snoopers |
| |
| for (p = argv [1] ; *p ; ++p) |
| *p = ' ' ; |
| |
| setupSigHandler () ; |
| |
| // Enter our big loop |
| |
| for (;;) |
| { |
| |
| if (!doDaemon) |
| printf ("-=-\nWaiting for a new connection...\n") ; |
| |
| if ((clientFd = setupServer (port)) < 0) |
| { |
| logMsg ("Unable to setup server: %s", strerror (errno)) ; |
| exit (EXIT_FAILURE) ; |
| } |
| |
| logMsg ("New connection from: %s.", getClientIP ()) ; |
| |
| if (!doDaemon) |
| printf ("Sending Greeting.\n") ; |
| |
| if (sendGreeting (clientFd) < 0) |
| { |
| logMsg ("Unable to send greeting message: %s", strerror (errno)) ; |
| closeServer (clientFd) ; |
| continue ; |
| } |
| |
| if (!doDaemon) |
| printf ("Sending Challenge.\n") ; |
| |
| if (sendChallenge (clientFd) < 0) |
| { |
| logMsg ("Unable to send challenge message: %s", strerror (errno)) ; |
| closeServer (clientFd) ; |
| continue ; |
| } |
| |
| if (!doDaemon) |
| printf ("Waiting for response.\n") ; |
| |
| if (getResponse (clientFd) < 0) |
| { |
| logMsg ("Connection closed waiting for response: %s", strerror (errno)) ; |
| closeServer (clientFd) ; |
| continue ; |
| } |
| |
| if (!passwordMatch (password)) |
| { |
| logMsg ("Password failure") ; |
| closeServer (clientFd) ; |
| continue ; |
| } |
| |
| logMsg ("Password OK - Starting") ; |
| |
| runRemoteCommands (clientFd) ; |
| closeServer (clientFd) ; |
| } |
| |
| return 0 ; |
| } |