wiringpid.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. * wiringPiD.c:
  3. * Copyright (c) 2012-2017 Gordon Henderson
  4. ***********************************************************************
  5. * This file is part of wiringPi:
  6. * https://projects.drogon.net/raspberry-pi/wiringpi/
  7. *
  8. * wiringPi is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * wiringPi is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
  20. ***********************************************************************
  21. */
  22. #include <arpa/inet.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <stdint.h>
  26. #include <unistd.h>
  27. #include <string.h>
  28. #include <stdarg.h>
  29. #include <syslog.h>
  30. #include <signal.h>
  31. #include <errno.h>
  32. #include <wiringPi.h>
  33. #include <wpiExtensions.h>
  34. #include "drcNetCmd.h"
  35. #include "network.h"
  36. #include "runRemote.h"
  37. #include "daemonise.h"
  38. #define PIDFILE "/var/run/wiringPiD.pid"
  39. // Globals
  40. static const char *usage = "[-h] [-d] [-g | -1 | -z] [[-x extension:pin:params] ...] password" ;
  41. static int doDaemon = FALSE ;
  42. //
  43. static void logMsg (const char *message, ...)
  44. {
  45. va_list argp ;
  46. char buffer [1024] ;
  47. va_start (argp, message) ;
  48. vsnprintf (buffer, 1023, message, argp) ;
  49. va_end (argp) ;
  50. if (doDaemon)
  51. syslog (LOG_DAEMON | LOG_INFO, "%s", buffer) ;
  52. else
  53. printf ("%s\n", buffer) ;
  54. }
  55. /*
  56. * sigHandler:
  57. * setupSigHandler:
  58. * Somehing has happened that would normally terminate the program so try
  59. * to close down nicely.
  60. *********************************************************************************
  61. */
  62. void sigHandler (int sig)
  63. {
  64. logMsg ("Exiting on signal %d: %s", sig, strsignal (sig)) ;
  65. (void)unlink (PIDFILE) ;
  66. exit (EXIT_FAILURE) ;
  67. }
  68. void setupSigHandler (void)
  69. {
  70. struct sigaction action ;
  71. sigemptyset (&action.sa_mask) ;
  72. action.sa_flags = 0 ;
  73. // Ignore what we can
  74. action.sa_handler = SIG_IGN ;
  75. sigaction (SIGHUP, &action, NULL) ;
  76. sigaction (SIGTTIN, &action, NULL) ;
  77. sigaction (SIGTTOU, &action, NULL) ;
  78. // Trap what we can to exit gracefully
  79. action.sa_handler = sigHandler ;
  80. sigaction (SIGINT, &action, NULL) ;
  81. sigaction (SIGQUIT, &action, NULL) ;
  82. sigaction (SIGILL, &action, NULL) ;
  83. sigaction (SIGABRT, &action, NULL) ;
  84. sigaction (SIGFPE, &action, NULL) ;
  85. sigaction (SIGSEGV, &action, NULL) ;
  86. sigaction (SIGPIPE, &action, NULL) ;
  87. sigaction (SIGALRM, &action, NULL) ;
  88. sigaction (SIGTERM, &action, NULL) ;
  89. sigaction (SIGUSR1, &action, NULL) ;
  90. sigaction (SIGUSR2, &action, NULL) ;
  91. sigaction (SIGCHLD, &action, NULL) ;
  92. sigaction (SIGTSTP, &action, NULL) ;
  93. sigaction (SIGBUS, &action, NULL) ;
  94. }
  95. /*
  96. * The works...
  97. *********************************************************************************
  98. */
  99. int main (int argc, char *argv [])
  100. {
  101. int clientFd ;
  102. char *p, *password ;
  103. int i ;
  104. int port = DEFAULT_SERVER_PORT ;
  105. int wpiSetup = 0 ;
  106. if (argc < 2)
  107. {
  108. fprintf (stderr, "Usage: %s %s\n", argv [0], usage) ;
  109. exit (EXIT_FAILURE) ;
  110. }
  111. // Help?
  112. if (strcasecmp (argv [1], "-h") == 0)
  113. {
  114. printf ("Usage: %s %s\n", argv [0], usage) ;
  115. return 0 ;
  116. }
  117. // Daemonize?
  118. // Must come before the other args as e.g. some extensions
  119. // open files which get closed on daemonise...
  120. if (strcasecmp (argv [1], "-d") == 0)
  121. {
  122. if (geteuid () != 0)
  123. {
  124. fprintf (stderr, "%s: Must be root to run as a daemon.\n", argv [0]) ;
  125. exit (EXIT_FAILURE) ;
  126. }
  127. doDaemon = TRUE ;
  128. daemonise (PIDFILE) ;
  129. for (i = 2 ; i < argc ; ++i)
  130. argv [i - 1] = argv [i] ;
  131. --argc ;
  132. }
  133. // Scan all other arguments
  134. while (*argv [1] == '-')
  135. {
  136. // Look for wiringPi setup arguments:
  137. // Same as the gpio command and rtb.
  138. // -g - bcm_gpio
  139. if (strcasecmp (argv [1], "-g") == 0)
  140. {
  141. if (wpiSetup == 0)
  142. {
  143. logMsg ("BCM_GPIO mode selected") ;
  144. wiringPiSetupGpio () ;
  145. }
  146. for (i = 2 ; i < argc ; ++i)
  147. argv [i - 1] = argv [i] ;
  148. --argc ;
  149. ++wpiSetup ;
  150. continue ;
  151. }
  152. // -1 - physical pins
  153. if (strcasecmp (argv [1], "-1") == 0)
  154. {
  155. if (wpiSetup == 0)
  156. {
  157. logMsg ("GPIO-PHYS mode selected") ;
  158. wiringPiSetupPhys () ;
  159. }
  160. for (i = 2 ; i < argc ; ++i)
  161. argv [i - 1] = argv [i] ;
  162. --argc ;
  163. ++wpiSetup ;
  164. continue ;
  165. }
  166. // -z - no wiringPi - blocks remotes accessing local pins
  167. if (strcasecmp (argv [1], "-z") == 0)
  168. {
  169. if (wpiSetup == 0)
  170. logMsg ("No GPIO mode selected") ;
  171. for (i = 2 ; i < argc ; ++i)
  172. argv [i - 1] = argv [i] ;
  173. --argc ;
  174. noLocalPins = TRUE ;
  175. ++wpiSetup ;
  176. continue ;
  177. }
  178. // -p to select the port
  179. if (strcasecmp (argv [1], "-p") == 0)
  180. {
  181. if (argc < 3)
  182. {
  183. logMsg ("-p missing extension port") ;
  184. exit (EXIT_FAILURE) ;
  185. }
  186. logMsg ("Setting port to: %s", argv [2]) ;
  187. port = atoi (argv [2]) ;
  188. if ((port < 1) || (port > 65535))
  189. {
  190. logMsg ("Invalid server port: %d", port) ;
  191. exit (EXIT_FAILURE) ;
  192. }
  193. // Shift args down by 2
  194. for (i = 3 ; i < argc ; ++i)
  195. argv [i - 2] = argv [i] ;
  196. argc -= 2 ;
  197. continue ;
  198. }
  199. // Check for -x argument to load in a new extension
  200. // -x extension:base:args
  201. // Can load many modules to extend the daemon.
  202. if (strcasecmp (argv [1], "-x") == 0)
  203. {
  204. if (argc < 3)
  205. {
  206. logMsg ("-x missing extension name:data:etc.") ;
  207. exit (EXIT_FAILURE) ;
  208. }
  209. logMsg ("Loading extension: %s", argv [2]) ;
  210. if (!loadWPiExtension (argv [0], argv [2], TRUE))
  211. {
  212. logMsg ("Extension load failed: %s", strerror (errno)) ;
  213. exit (EXIT_FAILURE) ;
  214. }
  215. // Shift args down by 2
  216. for (i = 3 ; i < argc ; ++i)
  217. argv [i - 2] = argv [i] ;
  218. argc -= 2 ;
  219. continue ;
  220. }
  221. logMsg ("Invalid parameter: %s", argv [1]) ;
  222. exit (EXIT_FAILURE) ;
  223. }
  224. // Default to wiringPi mode
  225. if (wpiSetup == 0)
  226. {
  227. logMsg ("WiringPi GPIO mode selected") ;
  228. wiringPiSetup () ;
  229. }
  230. // Finally, should just be one arg left - the password...
  231. if (argc != 2)
  232. {
  233. logMsg ("No password supplied") ;
  234. exit (EXIT_FAILURE) ;
  235. }
  236. if (strlen (argv [1]) < 6)
  237. {
  238. logMsg ("Password too short - at least 6 chars, not %d", strlen (argv [1])) ;
  239. exit (EXIT_FAILURE) ;
  240. }
  241. if ((password = malloc (strlen (argv [1]) + 1)) == NULL)
  242. {
  243. logMsg ("Out of memory") ;
  244. exit (EXIT_FAILURE) ;
  245. }
  246. strcpy (password, argv [1]) ;
  247. // Wipe out the password on the command-line in a vague attempt to try to
  248. // hide it from snoopers
  249. for (p = argv [1] ; *p ; ++p)
  250. *p = ' ' ;
  251. setupSigHandler () ;
  252. // Enter our big loop
  253. for (;;)
  254. {
  255. if (!doDaemon)
  256. printf ("-=-\nWaiting for a new connection...\n") ;
  257. if ((clientFd = setupServer (port)) < 0)
  258. {
  259. logMsg ("Unable to setup server: %s", strerror (errno)) ;
  260. exit (EXIT_FAILURE) ;
  261. }
  262. logMsg ("New connection from: %s.", getClientIP ()) ;
  263. if (!doDaemon)
  264. printf ("Sending Greeting.\n") ;
  265. if (sendGreeting (clientFd) < 0)
  266. {
  267. logMsg ("Unable to send greeting message: %s", strerror (errno)) ;
  268. closeServer (clientFd) ;
  269. continue ;
  270. }
  271. if (!doDaemon)
  272. printf ("Sending Challenge.\n") ;
  273. if (sendChallenge (clientFd) < 0)
  274. {
  275. logMsg ("Unable to send challenge message: %s", strerror (errno)) ;
  276. closeServer (clientFd) ;
  277. continue ;
  278. }
  279. if (!doDaemon)
  280. printf ("Waiting for response.\n") ;
  281. if (getResponse (clientFd) < 0)
  282. {
  283. logMsg ("Connection closed waiting for response: %s", strerror (errno)) ;
  284. closeServer (clientFd) ;
  285. continue ;
  286. }
  287. if (!passwordMatch (password))
  288. {
  289. logMsg ("Password failure") ;
  290. closeServer (clientFd) ;
  291. continue ;
  292. }
  293. logMsg ("Password OK - Starting") ;
  294. runRemoteCommands (clientFd) ;
  295. closeServer (clientFd) ;
  296. }
  297. return 0 ;
  298. }