Allow logging to be disabled, rename 'add' account
[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 <stdbool.h>
13 #include <string.h>
14 #include <signal.h>
15 #include "common.h"
16 #include <termios.h>
17 #include <unistd.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <stdarg.h>
21 #include <syslog.h>
22 #include <pthread.h>
23 #include "../cokebank.h"
24
25 // === IMPORTS ===
26 extern void     Init_Handlers(void);
27 extern void     Load_Itemlist(void);
28 extern void     Server_Start(void);
29 extern int      gbServer_RunInBackground;
30 extern int      giServer_Port;
31 extern const char       *gsItemListFile;
32 extern const char       *gsCoke_ModbusAddress;
33 extern const char       *gsDoor_SerialPort;
34 extern bool     gbSyslogEnabled;
35
36 // === PROTOTYPES ===
37 void    *Periodic_Thread(void *Unused);
38
39 // === GLOBALS ===
40  int    giDebugLevel = 0;
41  int    gbNoCostMode = 0;
42 const char      *gsCokebankPath = "cokebank.db";
43 // - Functions called every 20s (or so)
44 #define ciMaxPeriodics  10
45 struct sPeriodicCall {
46         void    (*Function)(void);
47 }       gaPeriodicCalls[ciMaxPeriodics];
48 pthread_t       gTimerThread;
49
50 // === CODE ===
51 void sigint_handler()
52 {
53         exit(0);
54 }
55
56 void PrintUsage(const char *progname)
57 {
58         fprintf(stderr, "Usage: %s\n", progname);
59         fprintf(stderr, "  -f,--configfile\n");
60         fprintf(stderr, "        Set the config file path (default `dispsrv.conf')\n");
61         fprintf(stderr, "  -d    Set debug level (0 - 2, default 0)\n");
62         fprintf(stderr, "  --[dont-]daemonise\n");
63         fprintf(stderr, "        Run (or explicitly don't run) the server disconnected from the terminal\n");
64 }
65
66 int main(int argc, char *argv[])
67 {
68          int    i;
69         const char      *config_file = "dispsrv.conf";
70
71         // Parse Arguments
72         for( i = 1; i < argc; i++ )
73         {
74                 char    *arg = argv[i];
75                 if( arg[0] == '-' && arg[1] != '-')
76                 {
77                         switch(arg[1])
78                         {
79                         case 'f':
80                                 if( i + 1 >= argc )     return -1;
81                                 config_file = argv[++i];
82                                 break;
83                         case 'd':
84                                 if( i + 1 >= argc )     return -1;
85                                 Config_AddValue("debug_level", argv[++i]);
86                                 giDebugLevel = atoi(argv[i]);
87                                 break;
88                         default:
89                                 // Usage Error
90                                 fprintf(stderr, "Unknown option '-%c'\n", arg[1]);
91                                 PrintUsage(argv[0]);
92                                 return -1;
93                         }
94                 }
95                 else if( arg[0] == '-' && arg[1] == '-' )
96                 {
97                         if( strcmp(arg, "--configfile") == 0 ) {
98                                 if( i + 1 >= argc )     return -1;
99                                 config_file = argv[++i];
100                         }
101                         else if( strcmp(arg, "--daemonise") == 0 ) {
102                                 Config_AddValue("daemonise", "true");
103                         }
104                         else if( strcmp(arg, "--dont-daemonise") == 0 ) {
105                                 Config_AddValue("daemonise", "false");
106                         }
107                         else {
108                                 // Usage error
109                                 fprintf(stderr, "Unknown option '%s'\n", arg);
110                                 PrintUsage(argv[0]);
111                                 return -1;
112                         }
113                 }
114                 else
115                 {
116                         // Usage Error
117                         PrintUsage(argv[0]);
118                         return -1;
119                 }
120         }
121
122         Config_ParseFile( config_file );
123
124         // Parse config values
125         gbServer_RunInBackground = Config_GetValue_Bool("daemonise", 0);
126         gsCokebankPath       = Config_GetValue("cokebank_database", 0);
127         gsDoor_SerialPort    = Config_GetValue("door_serial_port", 0);
128         gsCoke_ModbusAddress = Config_GetValue("coke_modbus_address", 0);
129         giServer_Port        = Config_GetValue_Int("server_port", 0);
130         gsItemListFile       = Config_GetValue("items_file", 0);
131
132         gbNoCostMode         = (Config_GetValue_Bool("test_mode", 0) == 1);
133         gbSyslogEnabled      = (Config_GetValue_Bool("disable_syslog", 0) == 0);
134
135         signal(SIGINT, sigint_handler);
136         signal(SIGTERM, sigint_handler);
137         
138         openlog("odispense2", 0, LOG_LOCAL4);
139         
140         if( Bank_Initialise(gsCokebankPath) )
141                 return -1;
142
143         Init_Handlers();
144
145         Load_Itemlist();
146         
147         Server_Start();
148         
149         if(gTimerThread)
150                 pthread_kill(gTimerThread, SIGKILL);
151
152         return 0;
153 }
154
155 void *Periodic_Thread(void *Unused __attribute__((unused)))
156 {
157          int    i;
158         
159         for( ;; )
160         {
161                 sleep(10);      // Sleep for a while
162 //              printf("Periodic firing\n");
163                 for( i = 0; i < ciMaxPeriodics; i ++ )
164                 {
165                         if( gaPeriodicCalls[i].Function )
166                                 gaPeriodicCalls[i].Function();
167                 }
168         }
169         return NULL;
170 }
171
172 void StartPeriodicThread(void)
173 {
174         pthread_create( &gTimerThread, NULL, Periodic_Thread, NULL );
175 }
176
177 void AddPeriodicFunction(void (*Fcn)(void))
178 {
179         int i;
180         for( i = 0; i < ciMaxPeriodics; i ++ )
181         {
182                 if( gaPeriodicCalls[i].Function )       continue;
183                 gaPeriodicCalls[i].Function = Fcn;
184                 return ;
185         }
186         
187         fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
188 }
189
190 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
191 {
192          int    ret;
193         
194         ret = regexec(regex, string, nMatches, matches, 0);
195         if( ret == REG_NOMATCH ) {
196                 return -1;
197         }
198         if( ret ) {
199                 size_t  len = regerror(ret, regex, NULL, 0);
200                 char    errorStr[len];
201                 regerror(ret, regex, errorStr, len);
202                 printf("string = '%s'\n", string);
203                 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
204                 exit(-1);
205         }
206         
207         return ret;
208 }
209
210 void CompileRegex(regex_t *regex, const char *pattern, int flags)
211 {
212          int    ret = regcomp(regex, pattern, flags);
213         if( ret ) {
214                 size_t  len = regerror(ret, regex, NULL, 0);
215                 char    errorStr[len];
216                 regerror(ret, regex, errorStr, len);
217                 fprintf(stderr, "Regex compilation failed - %s\n%s\n", errorStr, pattern);
218                 exit(-1);
219         }
220 }
221
222 // Serial helper
223 int InitSerial(const char *File, int BaudRate)
224 {
225         struct termios  info;
226          int    baud;
227          int    fd;
228         
229         fd = open(File, O_RDWR | O_NOCTTY | O_NONBLOCK);
230         if( fd == -1 )  return -1;
231         
232         switch(BaudRate)
233         {
234         case 1200:      baud = B1200;   break;
235         case 9600:      baud = B9600;   break;
236         case 115200:    baud = B115200; break;
237         default:
238                 fprintf(stderr, "ERROR: Invalid baud rate to InitSerial (%i)\n", BaudRate);
239                 exit(1);
240         }
241         
242         info.c_lflag = 0;       // Non-Canoical, No Echo
243         info.c_cflag = baud | CS8 | CLOCAL | CREAD;     // baud, 8N1
244         info.c_iflag = IGNCR;   // Ignore \r
245         info.c_oflag = 0;       // ???
246         cfsetspeed(&info, baud);
247         info.c_cc[VTIME] = 0;   // No time limit
248         info.c_cc[VMIN] = 1;    // Block until 1 char
249         
250         tcflush(fd, TCIFLUSH);
251         tcsetattr(fd, TCSANOW, &info);
252         
253         return fd;
254 }
255
256
257 /**
258  * \brief Create a formatted heap string
259  */
260 char *mkstr(const char *Format, ...)
261 {
262         va_list args;
263          int    len;
264         char    *ret;
265
266         va_start(args, Format);
267         len = vsnprintf(NULL, 0, Format, args);
268         va_end(args);
269
270         ret = malloc( len + 1 );
271         if(!ret)        return NULL;
272
273         va_start(args, Format);
274         vsprintf(ret, Format, args);
275         va_end(args);
276         
277         return ret;
278 }
279

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