Add define for compiling under RTLinux
[matches/MCTX3420.git] / server / main.c
1 /**
2  * @file main.c
3  * @brief main and its helper functions, signal handling and cleanup functions
4  */
5
6 // --- Custom headers --- //
7 #include "common.h"
8 #include "options.h"
9 #include "sensor.h"
10 #include "actuator.h"
11 #include "control.h"
12 #include "pin_test.h"
13 #include "bbb_pin_defines.h"
14
15 // --- Standard headers --- //
16 #include <syslog.h> // for system logging
17 #include <signal.h> // for signal handling
18
19
20 #ifdef REALTIME_VERSION
21 #include <time.h>
22 #include <sched.h>
23 #include <sys/mman.h>
24 #include <sys/utsname.h>
25 #endif //REALTIME_VERSION
26
27 // --- Variable definitions --- //
28 Options g_options; // options passed to program through command line arguments
29
30 // --- Function definitions --- //
31
32 /**
33  * Parse command line arguments, initialise g_options
34  * @param argc - Number of arguments
35  * @param argv - Array of argument strings
36  */
37 void ParseArguments(int argc, char ** argv)
38 {
39
40
41         g_options.program = argv[0]; // program name
42         g_options.verbosity = LOGDEBUG; // default log level
43         // Set the main directory
44         if (getcwd(g_options.root_dir, sizeof(g_options.root_dir)) == NULL)
45                 Fatal("Couldn't get current working directory - %s", strerror(errno));
46
47         clock_gettime(CLOCK_MONOTONIC, &(g_options.start_time)); // Start time
48
49
50         g_options.auth_method = AUTH_NONE;  // Don't use authentication
51         g_options.auth_uri = ""; // 
52         g_options.ldap_base_dn = "";
53         
54
55
56         for (int i = 1; i < argc; ++i)
57         {
58                 if (argv[i][0] != '-')
59                         Fatal("Unexpected argv[%d] - %s", i, argv[i]);
60
61                 if (i+1 >= argc || argv[i+1][0] == '-')
62                         Fatal("No argument following switch %s", argv[i]);
63                 
64                 if (strlen(argv[i]) > 2)
65                         Fatal("Human readable switches are not supported.");
66
67                 char * end = NULL;
68                 switch (argv[i][1])
69                 {
70                         // Set program verbosity
71                         case 'v':
72                                 g_options.verbosity = strtol(argv[++i], &end, 10);
73                                 break;
74                         // Enable/Disable pin test
75                         case 'p':
76                                 g_options.enable_pin = !(strtol(argv[++i], &end, 10));
77                                 break;
78                         // LDAP URI
79                         case 'A':
80                                 g_options.auth_uri = argv[++i];
81                                 break;
82                         // LDAP DN
83                         case 'd':
84                                 g_options.ldap_base_dn = argv[++i];
85                                 break;
86                         default:
87                                 Fatal("Unrecognised switch %s", argv[i]);
88                                 break;
89                 }
90
91                 if (end != NULL && *end != '\0')
92                         Fatal("argv[%d] -%c requires an integer (got \"%s\" instead)", i-1, argv[i-1][0], argv[i]);
93         }       
94
95         Log(LOGDEBUG, "Verbosity: %d", g_options.verbosity);
96         Log(LOGDEBUG, "Pin Module Enabled: %d", g_options.enable_pin);
97         Log(LOGDEBUG, "Auth URI: %s", g_options.auth_uri);
98         Log(LOGDEBUG, "LDAP Base DN: %s", g_options.ldap_base_dn);
99         Log(LOGDEBUG, "Root directory: %s", g_options.root_dir);
100
101         if (g_options.auth_uri[0] != '\0')
102         {
103                 //HACK...
104                 if (PathExists(g_options.auth_uri))
105                         g_options.auth_method = AUTH_SHADOW;
106                 else
107                         g_options.auth_method = AUTH_LDAP;
108         }
109         
110 }
111
112 /**
113  * Cleanup before the program exits
114  */
115 void Cleanup()
116 {
117         Log(LOGDEBUG, "Begin cleanup.");
118         Sensor_Cleanup();
119         //Actuator_Cleanup();
120         Log(LOGDEBUG, "Finish cleanup.");
121 }
122
123
124 #ifdef REALTIME_VERSION
125
126 #define MAX_SAFE_STACK (8*1024)
127 #define NSEC_PER_SEC (1000000000)
128
129 void stack_prefault()
130 {
131         unsigned char dummy[MAX_SAFE_STACK];
132         memset(dummy, 0, MAX_SAFE_STACK);
133         return;
134 }
135
136 bool is_realtime()
137 {
138         struct utsname u;
139         bool crit1 = 0;
140         bool crit2 = 0;
141         FILE * f;
142         uname(&u);
143         crit1 = (strcasestr(u.version, "PREEMPT RT") != NULL);
144         if (crit1 && ((f = fopen("/sys/kernel/realtime", "r")) != NULL))
145         {
146                 int flag;
147                 crit2 = ((fscanf(f, "%d", &flag) == 1) && (flag == 1));
148                 fclose(f);
149         }
150         return (crit1 && crit2);
151 }
152
153 #endif //REALTIME_VERSION
154
155 /**
156  * Main entry point; start worker threads, setup signal handling, wait for threads to exit, exit
157  * @param argc - Num args
158  * @param argv - Args
159  * @returns 0 on success, error code on failure
160  * NOTE: NEVER USE exit(3)! Instead call Thread_QuitProgram
161  */
162 int main(int argc, char ** argv)
163 {
164
165         // Open log before calling ParseArguments (since ParseArguments may call the Log functions)
166         openlog("mctxserv", LOG_PID | LOG_PERROR, LOG_USER);
167
168         ParseArguments(argc, argv); // Setup the g_options structure from program arguments
169
170         Log(LOGINFO, "Server started");
171
172
173         
174         #ifdef REALTIME_VERSION
175         
176         if (is_realtime())
177         {
178                 Log(LOGDEBUG, "Running under realtime kernel");
179         }
180         else
181         {
182                 Fatal("Not running under realtime kernel");
183         }
184         struct sched_param param;
185         param.sched_priority = 49;
186         if (sched_setscheduler(0, SCHED_FIFO, &param) < 0)
187                 Fatal("sched_setscheduler failed - %s", strerror(errno));
188         if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
189                 Fatal("mlockall failed - %s", strerror(errno));
190         stack_prefault();
191         #endif //REALTIME_VERSION
192
193         
194
195         Sensor_Init();
196         Actuator_Init();
197         Pin_Init();
198         
199         // Try and start things
200         
201         const char *ret;
202         if ((ret = Control_SetMode(CONTROL_START, "test")) != NULL)
203                 Fatal("Control_SetMode failed with '%s'", ret);
204         
205
206         // run request thread in the main thread
207         FCGI_RequestLoop(NULL);
208
209         
210         if ((ret = Control_SetMode(CONTROL_STOP, "test")) != NULL)
211                 Fatal("Control_SetMode failed with '%s'", ret);
212         
213         //Sensor_StopAll();
214         //Actuator_StopAll();
215
216         Pin_Close();
217
218         Cleanup();
219         return 0;
220 }
221
222

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