Gordons Projects

--> Projects Top-Level GIT

Bumped the version to 2.40 - correctly this time, I hope.
[wiringPi] / wiringPiD / wiringpid.c
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
23 #include <arpa/inet.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <syslog.h>
31 #include <signal.h>
32 #include <errno.h>
33
34 #include <wiringPi.h>
35 #include <wpiExtensions.h>
36
37 #include "drcNetCmd.h"
38 #include "network.h"
39 #include "runRemote.h"
40 #include "daemonise.h"
41
42
43 #define PIDFILE "/var/run/wiringPiD.pid"
44
45
46 // Globals
47
48 static const char *usage = "[-h] [-d] [-g | -1 | -z] [[-x extension:pin:params] ...] password" ;
49 static int doDaemon = FALSE ;
50
51 //
52
53 static void logMsg (const char *message, ...)
54 {
55   va_list argp ;
56   char buffer [1024] ;
57
58   va_start (argp, message) ;
59     vsnprintf (buffer, 1023, message, argp) ;
60   va_end (argp) ;
61
62   if (doDaemon)
63     syslog (LOG_DAEMON | LOG_INFO, "%s", buffer) ;
64   else
65     printf ("%s\n", buffer) ;
66 }
67
68
69 /*
70  * sigHandler:
71  * setupSigHandler:
72  *      Somehing has happened that would normally terminate the program so try
73  *      to close down nicely.
74  *********************************************************************************
75  */
76
77 void sigHandler (int sig)
78 {
79   logMsg ("Exiting on signal %d: %s", sig, strsignal (sig)) ;
80   (void)unlink (PIDFILE) ;
81   exit (EXIT_FAILURE) ;
82 }
83
84 void setupSigHandler (void)
85 {
86   struct sigaction action ;
87
88   sigemptyset (&action.sa_mask) ;
89   action.sa_flags = 0 ;
90
91 // Ignore what we can
92
93   action.sa_handler = SIG_IGN ;
94
95   sigaction (SIGHUP,  &action, NULL) ;
96   sigaction (SIGTTIN, &action, NULL) ;
97   sigaction (SIGTTOU, &action, NULL) ;
98
99 // Trap what we can to exit gracefully
100
101   action.sa_handler = sigHandler ;
102
103   sigaction (SIGINT,  &action, NULL) ;
104   sigaction (SIGQUIT, &action, NULL) ;
105   sigaction (SIGILL,  &action, NULL) ;
106   sigaction (SIGABRT, &action, NULL) ;
107   sigaction (SIGFPE,  &action, NULL) ;
108   sigaction (SIGSEGV, &action, NULL) ;
109   sigaction (SIGPIPE, &action, NULL) ;
110   sigaction (SIGALRM, &action, NULL) ;
111   sigaction (SIGTERM, &action, NULL) ;
112   sigaction (SIGUSR1, &action, NULL) ;
113   sigaction (SIGUSR2, &action, NULL) ;
114   sigaction (SIGCHLD, &action, NULL) ;
115   sigaction (SIGTSTP, &action, NULL) ;
116   sigaction (SIGBUS,  &action, NULL) ;
117 }
118
119
120 /*
121  * The works...
122  *********************************************************************************
123  */
124
125 int main (int argc, char *argv [])
126 {
127   int clientFd ;
128   char *p, *password ;
129   int i ;
130   int port = DEFAULT_SERVER_PORT ;
131   int wpiSetup = 0 ;
132
133   if (argc < 2)
134   {
135     fprintf (stderr, "Usage: %s %s\n", argv [0], usage) ;
136     exit (EXIT_FAILURE) ;
137   }
138
139 // Help?
140
141   if (strcasecmp (argv [1], "-h") == 0)
142   {
143     printf ("Usage: %s %s\n", argv [0], usage) ;
144     return 0 ;
145   }
146
147 // Daemonize?
148 //      Must come before the other args as e.g. some extensions
149 //      open files which get closed on daemonise...
150
151   if (strcasecmp (argv [1], "-d") == 0)
152   {
153     if (geteuid () != 0)
154     {
155       fprintf (stderr, "%s: Must be root to run as a daemon.\n", argv [0]) ;
156       exit (EXIT_FAILURE) ;
157     }
158
159     doDaemon = TRUE ;
160     daemonise (PIDFILE) ;
161
162     for (i = 2 ; i < argc ; ++i)
163       argv [i - 1] = argv [i] ;
164     --argc ;
165   }
166
167 // Scan all other arguments
168
169   while (*argv [1] == '-')
170   {
171
172 // Look for wiringPi setup arguments:
173 //      Same as the gpio command and rtb.
174
175 //      -g - bcm_gpio
176
177     if (strcasecmp (argv [1], "-g") == 0)
178     {
179       if (wpiSetup == 0)
180       {
181         logMsg ("BCM_GPIO mode selected") ;
182         wiringPiSetupGpio () ;
183       }
184
185       for (i = 2 ; i < argc ; ++i)
186         argv [i - 1] = argv [i] ;
187       --argc ;
188       ++wpiSetup ;
189       continue ;
190     }
191
192 //      -1 - physical pins
193
194     if (strcasecmp (argv [1], "-1") == 0)
195     {
196       if (wpiSetup == 0)
197       {
198         logMsg ("GPIO-PHYS mode selected") ;
199         wiringPiSetupPhys () ;
200       }
201
202       for (i = 2 ; i < argc ; ++i)
203         argv [i - 1] = argv [i] ;
204       --argc ;
205       ++wpiSetup ;
206       continue ;
207     }
208
209 //      -z  - no wiringPi - blocks remotes accessing local pins
210
211     if (strcasecmp (argv [1], "-z") == 0)
212     {
213       if (wpiSetup == 0)
214         logMsg ("No GPIO mode selected") ;
215
216       for (i = 2 ; i < argc ; ++i)
217         argv [i - 1] = argv [i] ;
218       --argc ;
219       noLocalPins = TRUE ;
220       ++wpiSetup ;
221       continue ;
222     }
223
224 // -p to select the port
225
226     if (strcasecmp (argv [1], "-p") == 0)
227     {
228       if (argc < 3)
229       {
230         logMsg ("-p missing extension port") ;
231         exit (EXIT_FAILURE) ;
232       }
233
234       logMsg ("Setting port to: %s", argv [2]) ;
235
236       port = atoi (argv [2]) ;
237       if ((port < 1) || (port > 65535))
238       {
239         logMsg ("Invalid server port: %d", port) ;
240         exit (EXIT_FAILURE) ;
241       }
242
243 // Shift args down by 2
244
245       for (i = 3 ; i < argc ; ++i)
246         argv [i - 2] = argv [i] ;
247       argc -= 2 ;
248
249       continue ;
250     }
251
252 // Check for -x argument to load in a new extension
253 //      -x extension:base:args
254 //      Can load many modules to extend the daemon.
255
256     if (strcasecmp (argv [1], "-x") == 0)
257     {
258       if (argc < 3)
259       {
260         logMsg ("-x missing extension name:data:etc.") ;
261         exit (EXIT_FAILURE) ;
262       }
263
264       logMsg ("Loading extension: %s", argv [2]) ;
265
266       if (!loadWPiExtension (argv [0], argv [2], TRUE))
267       {
268         logMsg ("Extension load failed: %s", strerror (errno)) ;
269         exit (EXIT_FAILURE) ;
270       }
271
272 // Shift args down by 2
273
274       for (i = 3 ; i < argc ; ++i)
275         argv [i - 2] = argv [i] ;
276       argc -= 2 ;
277
278       continue ;
279     }
280
281     logMsg ("Invalid parameter: %s", argv [1]) ;
282     exit (EXIT_FAILURE) ;
283   }
284
285 // Default to wiringPi mode
286
287   if (wpiSetup == 0)
288   {
289     logMsg ("WiringPi GPIO mode selected") ;
290     wiringPiSetup () ;
291   }
292
293 // Finally, should just be one arg left - the password...
294
295   if (argc != 2)
296   {
297     logMsg ("No password supplied") ;
298     exit (EXIT_FAILURE) ;
299   }
300
301   if (strlen (argv [1]) < 6)
302   {
303     logMsg ("Password too short - at least 6 chars, not %d", strlen (argv [1])) ;
304     exit (EXIT_FAILURE) ;
305   }
306
307   if ((password = malloc (strlen (argv [1]) + 1)) == NULL)
308   {
309     logMsg ("Out of memory") ;
310     exit (EXIT_FAILURE) ;
311   }
312   strcpy (password, argv [1]) ;
313
314 // Wipe out the password on the command-line in a vague attempt to try to
315 //      hide it from snoopers
316
317   for (p = argv [1] ; *p ; ++p)
318     *p = ' ' ;
319
320   setupSigHandler () ;
321  
322 // Enter our big loop
323
324   for (;;)
325   {
326
327     if (!doDaemon)
328       printf ("-=-\nWaiting for a new connection...\n") ;
329
330     if ((clientFd = setupServer (port)) < 0)
331     {
332       logMsg ("Unable to setup server: %s", strerror (errno)) ;
333       exit (EXIT_FAILURE) ;
334     }
335
336     logMsg ("New connection from: %s.", getClientIP ()) ;
337
338     if (!doDaemon)
339       printf ("Sending Greeting.\n") ;
340
341     if (sendGreeting (clientFd) < 0)
342     {
343       logMsg ("Unable to send greeting message: %s", strerror (errno)) ;
344       closeServer (clientFd) ;
345       continue ;
346     }
347
348     if (!doDaemon)
349       printf ("Sending Challenge.\n") ;
350
351     if (sendChallenge (clientFd) < 0)
352     {
353       logMsg ("Unable to send challenge message: %s", strerror (errno)) ;
354       closeServer (clientFd) ;
355       continue ;
356     }
357
358     if (!doDaemon)
359       printf ("Waiting for response.\n") ;
360
361     if (getResponse (clientFd) < 0)
362     {
363       logMsg ("Connection closed waiting for response: %s", strerror (errno)) ;
364       closeServer (clientFd) ;
365       continue ;
366     }
367
368     if (!passwordMatch (password))
369     {
370       logMsg ("Password failure") ;
371       closeServer (clientFd) ;
372       continue ;
373     }
374
375     logMsg ("Password OK - Starting") ;
376
377     runRemoteCommands (clientFd) ;
378     closeServer       (clientFd) ;
379   }
380
381   return 0 ;
382 }