1 /*
2  *
3  *   program:  sanityCheck
4  *   file:     main.c
5  *   author:   Todd Naugle
6  *   date:     11/17/2010
7  *
8  *   Desc:  Command line version of the sanity check functions found in jack
9 */
10 
11 #include <algorithm>
12 #include <stdio.h>
13 #include <string>
14 #include <vector>
15 
16 #include "systemtest.h"
17 
18 
19 using namespace std;
20 
21 typedef int (*testfuncPtr) ();
22 typedef int (*testfuncOpPtr) (string);
23 
24 typedef struct
25 {
26 	string			switchText;			// ie -option
27 	string			swOptionText;       // option arguments for just this swtich.
28 	string			descriptionText;	// Help Text on what this does
29 	string			failureText;		// What to say when this test fails
30 	bool			hasOption;			// Set true if this switch has option paramters
31 	testfuncPtr		functionPtr;		// Function to call
32 	testfuncOpPtr	opFunctionPtr;		// Function with option string to call
33 	string			optionArg;			// Storage used to hold any options passed in by the user
34 } testRecord;
35 
36 static vector<testRecord>	gTestSet;
37 
38 static vector<string>		gValidSwitchList;
39 static vector<string>		gSwitchDescriptionList;
40 
41 static vector<string>		gSwitchesReceived;
42 
43 int
ExecuteAll()44 ExecuteAll()
45 {
46 	bool OK = true;
47 
48 	OK &= system_user_can_rtprio();
49 
50 	if (system_has_frequencyscaling()) {
51 		OK &= !system_uses_frequencyscaling();
52 	}
53 
54 	OK &= !(system_memlock_amount() == 0);
55 
56 	return OK;
57 }
58 
59 int
HasGroup(string name)60 HasGroup(string name)
61 {
62 	return system_has_group(name.c_str());
63 }
64 
65 int
IsMemberOfGroup(string name)66 IsMemberOfGroup(string name)
67 {
68 	return system_user_in_group(name.c_str());
69 }
70 
71 int
CheckFreqScaling()72 CheckFreqScaling()
73 {
74 	bool OK = true;
75 
76 	if (system_has_frequencyscaling()) {
77 		OK &= !system_uses_frequencyscaling();
78 	}
79 
80 	return OK;
81 }
82 
83 int
CheckMemoryLocking()84 CheckMemoryLocking()
85 {
86 	return !(system_memlock_amount() == 0);
87 }
88 
89 int
PrintUsage()90 PrintUsage()
91 {
92 	printf("\n");
93 	printf("  sanityCheck - A program to verify proper system settings for use with audio applications (Ardour/Jack/Mixbus).\n");
94 	printf("\n");
95 	printf("  Usage:  sanityCheck [OPTIONS]\n");
96 	printf("\n");
97 	printf("  Options are as follows:\n");
98 	printf("\n");
99 	printf("\n");
100 
101 	vector<testRecord>::iterator		itr;
102 
103 	for (itr = gTestSet.begin(); itr != gTestSet.end(); ++itr) {
104 		printf("%20s %s :\t%s\n", (*itr).switchText.c_str(), (*itr).swOptionText.c_str(), (*itr).descriptionText.c_str());
105 	}
106 
107 	printf("\n");
108 
109 	return true;
110 }
111 
112 void
DefineSwitches()113 DefineSwitches()
114 {
115 	testRecord rec;
116 
117 	// Global switches
118 	rec.switchText = "-a";
119 	rec.swOptionText = "";
120 	rec.descriptionText = "Checks for a working RT system. Same as -rt -freqscaling -memlock";
121 	rec.failureText = "";
122 	rec.hasOption = false;
123 	rec.functionPtr = &ExecuteAll;
124 	rec.optionArg = "";
125 	gTestSet.push_back(rec);
126 
127 	rec.switchText = "-h";
128 	rec.swOptionText = "";
129 	rec.descriptionText = "Print usage";
130 	rec.failureText = "";
131 	rec.hasOption = false;
132 	rec.functionPtr = &PrintUsage;
133 	rec.optionArg = "";
134 	gTestSet.push_back(rec);
135 
136 	// Switches for various tests that can be performed.
137 	rec.switchText = "-rt";
138 	rec.swOptionText = "";
139 	rec.descriptionText = "Verify that the user can run tasks with realtime priority";
140 	rec.failureText = "";
141 	rec.hasOption = false;
142 	rec.functionPtr = &system_user_can_rtprio;
143 	rec.optionArg = "";
144 	gTestSet.push_back(rec);
145 
146 	rec.switchText = "-hasrtlimits";
147 	rec.swOptionText = "";
148 	rec.descriptionText = "Verify the system has a limits.conf and the audio group can use realtime";
149 	rec.failureText = "";
150 	rec.hasOption = false;
151 	rec.functionPtr = &system_has_rtprio_limits_conf;
152 	rec.optionArg = "";
153 	gTestSet.push_back(rec);
154 
155 	rec.switchText = "-hasgroup";
156 	rec.swOptionText = "<groupname>";
157 	rec.descriptionText = "Verify that the system has a group named <groupname>";
158 	rec.failureText = "";
159 	rec.hasOption = true;
160 	rec.opFunctionPtr = &HasGroup;
161 	rec.optionArg = "";
162 	gTestSet.push_back(rec);
163 
164 	rec.switchText = "-hasaudiogroup";
165 	rec.swOptionText = "";
166 	rec.descriptionText = "Verify that the system has an audio group (audio or jackuser) defined";
167 	rec.failureText = "";
168 	rec.hasOption = false;
169 	rec.functionPtr = &system_has_audiogroup;
170 	rec.optionArg = "";
171 	gTestSet.push_back(rec);
172 
173 	rec.switchText = "-memberofgroup";
174 	rec.swOptionText = "<groupname>";
175 	rec.descriptionText = "Verify that the user is a member of the group named <groupname>";
176 	rec.failureText = "";
177 	rec.hasOption = true;
178 	rec.opFunctionPtr = &IsMemberOfGroup;
179 	rec.optionArg = "";
180 	gTestSet.push_back(rec);
181 
182 	rec.switchText = "-memberaudiogroup";
183 	rec.swOptionText = "";
184 	rec.descriptionText = "Verify that the user is a member of the audio group (audio or jackuser)";
185 	rec.failureText = "";
186 	rec.hasOption = false;
187 	rec.functionPtr = &system_user_in_audiogroup;
188 	rec.optionArg = "";
189 	gTestSet.push_back(rec);
190 
191 	rec.switchText = "-freqscaling";
192 	rec.swOptionText = "";
193 	rec.descriptionText = "Check to see if frequency scaling is being used by the CPU";
194 	rec.failureText = "";
195 	rec.hasOption = false;
196 	rec.functionPtr = &CheckFreqScaling;
197 	rec.optionArg = "";
198 	gTestSet.push_back(rec);
199 
200 	rec.switchText = "-memlock";
201 	rec.swOptionText = "";
202 	rec.descriptionText = "Check to see if the user is able to lock memory";
203 	rec.failureText = "";
204 	rec.hasOption = false;
205 	rec.functionPtr = &CheckMemoryLocking;
206 	rec.optionArg = "";
207 	gTestSet.push_back(rec);
208 
209 }
210 
211 bool
ParseSwitches(int argc,char ** argv)212 ParseSwitches(
213 	int		argc,
214 	char	**argv)
215 {
216 	string	tmp;
217 	vector<testRecord>::iterator	itr;
218 	bool	OK = true;
219 	int	i;
220 
221 	if (argc == 1) {
222 		gSwitchesReceived.push_back("-a");
223 	}
224 	else {
225 		for (i = 1; i < argc && OK == true; i++) {
226 			tmp = argv[i];
227 
228 			for (itr = gTestSet.begin(); itr != gTestSet.end(); ++itr) {
229 				if (tmp == (*itr).switchText) {
230 					if ((*itr).hasOption == true) {
231 						if (++i < argc) {
232 							string	op = argv[i];
233 							if (op[0] == '-') {
234 								// reqiured option for this switch is missing
235 								--i;
236 								OK = false;
237 								break;
238 							}
239 							(*itr).optionArg = op;
240 							break;
241 						}
242 						else {
243 							// reqiured option for this switch is missing
244 							--i;
245 							OK = false;
246 							break;
247 						}
248 					}
249 					break;
250 				}
251 			}
252 
253 			if (OK && itr != gTestSet.end()) {
254 				// Known option switch found
255 				gSwitchesReceived.push_back(tmp);
256 			}
257 			else {
258 				// Unknown option
259 				OK = false;
260 			}
261 		}
262 	}
263 
264 	if (OK) {
265 		// All switches are at least valid, now check to make sure they are all valid to
266 		// be used together.
267 
268 		if (gSwitchesReceived.size() > 1) {
269 			// make sure help is not mixed with other options
270 			vector<string>::iterator	swItr;
271 			tmp = "-h";
272 
273 			swItr = find(gSwitchesReceived.begin(), gSwitchesReceived.end(), tmp);
274 
275 			if (swItr != gSwitchesReceived.end()) {
276 				gSwitchesReceived.clear();
277 				gSwitchesReceived.push_back("-h");
278 			}
279 
280 			// make sure -a is only used by itself
281 			tmp = "-a";
282 			swItr = find(gSwitchesReceived.begin(), gSwitchesReceived.end(), tmp);
283 
284 			if (swItr != gSwitchesReceived.end()) {
285 				gSwitchesReceived.clear();
286 				gSwitchesReceived.push_back("-a");
287 			}
288 		}
289 
290 		return true;
291 	}
292 	else {
293 		fprintf(stderr, "\n");
294 		fprintf(stderr, "ERROR - Invalid Option: %s\n", (const char *) argv[--i]);
295 		fprintf(stderr, "Check syntax\n");
296 		PrintUsage();
297 		return false;
298 	}
299 }
300 
301 bool
Execute()302 Execute()
303 {
304 	bool OK = true;
305 	vector<string>::iterator	itr;
306 	vector<testRecord>::iterator	testItr;
307 
308 	for (itr = gSwitchesReceived.begin(); itr != gSwitchesReceived.end(); ++itr) {
309 		for (testItr = gTestSet.begin(); testItr != gTestSet.end(); ++testItr) {
310 			if ((*itr) == (*testItr).switchText) {
311 				break;
312 			}
313 		}
314 
315 		bool result;
316 		if ((*testItr).hasOption) {
317 			result = ((*testItr).opFunctionPtr((*testItr).optionArg) != 0);
318 		}
319 		else {
320 			result = ((*testItr).functionPtr() != 0);
321 		}
322 
323 		if (result == 0) {
324 			// Check for a Failure message and print it if found.
325 			if (!(*testItr).failureText.empty()) {
326 				printf("\n%s\n", (*testItr).failureText.c_str());
327 			}
328 		}
329 
330 		OK &= result;
331 	}
332 
333 	return OK;
334 }
335 
336 int
main(int argc,char ** argv)337 main(
338 	int		 argc,
339 	char 	**argv)
340 {
341 	int status = 0;
342 
343 	DefineSwitches();
344 
345 	if (ParseSwitches(argc, argv)) {
346 		if (Execute() == false) {
347 			printf("\nSanity Check Failed!\n\n");
348 			status = -1;
349 		}
350 		else {
351 			printf("\nSanity Check OK!\n\n");
352 		}
353 	}
354 	else {
355 		status = -1;
356 	}
357 
358 	return status;
359 }
360