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

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