You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
382 lines
8.1 KiB
382 lines
8.1 KiB
/* |
|
* 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 ; |
|
}
|
|
|