a8d8d32dd57ef641c9fe7b0d85dc6b485cf4dbc9
[tpg/opendispense2.git] / src / server / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * main.c - Initialisation Code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <signal.h>
14 #include "common.h"
15 #include <termios.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <stdarg.h>
20 #include <syslog.h>
21 #include <pthread.h>
22 #include "../cokebank.h"
23
24 // === IMPORTS ===
25 extern void     Init_Handlers(void);
26 extern void     Load_Itemlist(void);
27 extern void     Server_Start(void);
28 extern int      gbServer_RunInBackground;
29 extern int      giServer_Port;
30 extern char     *gsItemListFile;
31 extern char     *gsCoke_SerialPort;
32 extern char     *gsSnack_SerialPort;
33 extern char     *gsDoor_Password;
34
35 // === PROTOTYPES ===
36 void    *Periodic_Thread(void *Unused);
37
38 // === GLOBALS ===
39  int    giDebugLevel = 0;
40 char    *gsCokebankPath = "cokebank.db";
41 // - Functions called every 20s (or so)
42 #define ciMaxPeriodics  10
43 struct sPeriodicCall {
44         void    (*Function)(void);
45 }       gaPeriodicCalls[ciMaxPeriodics];
46 pthread_t       gTimerThread;
47
48 // === CODE ===
49 void sigint_handler()
50 {
51         exit(0);
52 }
53
54 void PrintUsage(const char *progname)
55 {
56         fprintf(stderr, "Usage: %s\n", progname);
57         fprintf(stderr, "  -p    Set server port (default 11020)\n");
58         fprintf(stderr, "  -d    Set debug level (0 - 2, default 0)\n");
59         fprintf(stderr, "  --itemsfile\n");
60         fprintf(stderr, "        Set debug level (0 - 2, default 0)\n");
61         fprintf(stderr, "  --cokeport\n");
62         fprintf(stderr, "        Coke machine serial port (Default \"/dev/ttyS0\")\n");
63         fprintf(stderr, "  --doorpass\n");
64         fprintf(stderr, "        Door LAT password file (Default empty password)\n");
65         fprintf(stderr, "  --cokebank\n");
66         fprintf(stderr, "        Coke bank database file (Default \"cokebank.db\")\n");
67 }
68
69 int main(int argc, char *argv[])
70 {
71          int    i;
72         
73         // Parse Arguments
74         for( i = 1; i < argc; i++ )
75         {
76                 char    *arg = argv[i];
77                 if( arg[0] == '-' && arg[1] != '-')
78                 {
79                         switch(arg[1])
80                         {
81                         case 'p':
82                                 if( i + 1 >= argc )     return -1;
83                                 giServer_Port = atoi(argv[++i]);
84                                 break;
85                         case 'd':
86                                 if( i + 1 >= argc )     return -1;
87                                 giDebugLevel = atoi(argv[++i]);
88                                 break;
89                         case 'D':
90                                 gbServer_RunInBackground = 1;
91                                 return -1;
92                         default:
93                                 // Usage Error?
94                                 PrintUsage(argv[0]);
95                                 return -1;
96                         }
97                 }
98                 else if( arg[0] == '-' && arg[1] == '-' ) {
99                         if( strcmp(arg, "--itemsfile") == 0 ) {
100                                 if( i + 1 >= argc )     return -1;
101                                 gsItemListFile = argv[++i];
102                         }
103                         else if( strcmp(arg, "--cokeport") == 0 ) {
104                                 if( i + 1 >= argc )     return -1;
105                                 gsCoke_SerialPort = argv[++i];
106                         }
107                         else if( strcmp(arg, "--snackport") == 0 ) {
108                                 if( i + 1 >= argc )     return -1;
109                                 gsSnack_SerialPort = argv[++i];
110                         }
111                         else if( strcmp(arg, "--doorpass") == 0 ) {
112                                 FILE    *fp;
113                                 char    buf[30];
114                                 if( i + 1 >= argc )     return -1;
115                                 fp = fopen(argv[++i], "r");
116                                 if( !fp ) {
117                                         fprintf(stderr, "ERROR: Unable to read password file\n");
118                                         perror("reading LAT password");
119                                         return -1;
120                                 }
121                                 fgets(buf, sizeof buf, fp);
122                                 fclose(fp);
123                                 gsDoor_Password = strdup(buf);
124                         }
125                         else if( strcmp(arg, "--cokebank") == 0 ) {
126                                 if( i + 1 >= argc )     return -1;
127                                 gsCokebankPath = argv[++i];
128                         }
129                         else if( strcmp(arg, "--daemonise") == 0 ) {
130                                 gbServer_RunInBackground = 1;
131                         }
132                         else if( strcmp(arg, "--dont-daemonise") == 0 ) {
133                                 gbServer_RunInBackground = 0;
134                         }
135                         else {
136                                 // Usage error?
137                                 PrintUsage(argv[0]);
138                                 return -1;
139                         }
140                 }
141                 else {
142                         // Usage Error?
143                         PrintUsage(argv[0]);
144                         return -1;
145                 }
146         }
147         
148         signal(SIGINT, sigint_handler);
149         signal(SIGTERM, sigint_handler);
150         
151         openlog("odispense2", 0, LOG_LOCAL4);
152         
153         if( Bank_Initialise(gsCokebankPath) )
154                 return -1;
155
156         Init_Handlers();
157
158         Load_Itemlist();
159         
160         Server_Start();
161         
162         pthread_kill(gTimerThread, SIGKILL);
163
164         return 0;
165 }
166
167 void *Periodic_Thread(void *Unused)
168 {
169          int    i;
170         Unused = NULL;  // quiet, gcc
171         
172         for( ;; )
173         {
174                 sleep(10);      // Sleep for a while
175 //              printf("Periodic firing\n");
176                 for( i = 0; i < ciMaxPeriodics; i ++ )
177                 {
178                         if( gaPeriodicCalls[i].Function )
179                                 gaPeriodicCalls[i].Function();
180                 }
181         }
182         return NULL;
183 }
184
185 void StartPeriodicThread(void)
186 {
187         pthread_create( &gTimerThread, NULL, Periodic_Thread, NULL );
188 }
189
190 void AddPeriodicFunction(void (*Fcn)(void))
191 {
192         int i;
193         for( i = 0; i < ciMaxPeriodics; i ++ )
194         {
195                 if( gaPeriodicCalls[i].Function )       continue;
196                 gaPeriodicCalls[i].Function = Fcn;
197                 return ;
198         }
199         
200         fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
201 }
202
203 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
204 {
205          int    ret;
206         
207         ret = regexec(regex, string, nMatches, matches, 0);
208         if( ret == REG_NOMATCH ) {
209                 return -1;
210         }
211         if( ret ) {
212                 size_t  len = regerror(ret, regex, NULL, 0);
213                 char    errorStr[len];
214                 regerror(ret, regex, errorStr, len);
215                 printf("string = '%s'\n", string);
216                 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
217                 exit(-1);
218         }
219         
220         return ret;
221 }
222
223 void CompileRegex(regex_t *regex, const char *pattern, int flags)
224 {
225          int    ret = regcomp(regex, pattern, flags);
226         if( ret ) {
227                 size_t  len = regerror(ret, regex, NULL, 0);
228                 char    errorStr[len];
229                 regerror(ret, regex, errorStr, len);
230                 fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
231                 exit(-1);
232         }
233 }
234
235 // Serial helper
236 int InitSerial(const char *File, int BaudRate)
237 {
238         struct termios  info;
239          int    baud;
240          int    fd;
241         
242         fd = open(File, O_RDWR | O_NOCTTY | O_NONBLOCK);
243         if( fd == -1 )  return -1;
244         
245         switch(BaudRate)
246         {
247         case 9600:      baud = B9600;   break;
248         default:        close(fd);      return -1;
249         }
250         
251         info.c_lflag = 0;       // Non-Canoical, No Echo
252         info.c_cflag = baud | CS8 | CLOCAL | CREAD;     // baud, 8N1
253         cfsetspeed(&info, baud);
254         info.c_cc[VTIME] = 0;   // No time limit
255         info.c_cc[VMIN] = 1;    // Block until 1 char
256         
257         tcflush(fd, TCIFLUSH);
258         tcsetattr(fd, TCSANOW, &info);
259         
260         return fd;
261 }
262
263
264 /**
265  * \brief Create a formatted heap string
266  */
267 char *mkstr(const char *Format, ...)
268 {
269         va_list args;
270          int    len;
271         char    *ret;
272
273         va_start(args, Format);
274         len = vsnprintf(NULL, 0, Format, args);
275         va_end(args);
276
277         ret = malloc( len + 1 );
278         if(!ret)        return NULL;
279
280         va_start(args, Format);
281         vsprintf(ret, Format, args);
282         va_end(args);
283         
284         return ret;
285 }
286

UCC git Repository :: git.ucc.asn.au