1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include <stdio.h>
26 #include <ctype.h>
|
27 krisbash 1.3 #include <pal/strings.h>
|
28 mike 1.1 #include <base/list.h>
|
29 krisbash 1.3 #include <pal/format.h>
30 #include <pal/file.h>
31 #include <base/log.h>
|
32 mike 1.1 #include "regfile.h"
33
|
34 krisbash 1.3 #define REG_INDICATION_CLASS "INDICATIONCLASS"
35
|
36 mike 1.1 // Parse an identifies of the form "[A-Za-z_][A-Za-z_0-9]*"
|
37 krisbash 1.3 _Return_type_success_(return == 0)
38 static int _ParseIdentifier(_Inout_ CharPtr* pOut, _Out_ CharPtr* start, _Out_ CharPtr* end)
|
39 mike 1.1 {
40 char* p = *pOut;
41
42 /* Skip leading whitespace */
|
43 krisbash 1.3 while (*p && isspace((unsigned char)(*p)))
|
44 mike 1.1 p++;
45
46 /* Set start of identifier */
47 *start = p;
48
49 /* Expect [A-Za-z_] characters */
50 if (!isalpha((unsigned char)(*p)) && *p != '_')
51 return -1;
52
53 /* Skip [A-Za-z_0-9] characters */
|
54 krisbash 1.3 while (*p && (isalnum((unsigned char)(*p)) || *p == '_'))
|
55 mike 1.1 p++;
56
57 /* Set end of identifier */
58 *end = p;
59
60 *pOut = p;
61 return 0;
62 }
63
64 // Parase class path of the form "CLASS1:CLASS2:CLASS3"
|
65 krisbash 1.3 _Return_type_success_(return == 0)
66 static int _ParseClassPath(_Inout_ CharPtr* pOut, _Out_ CharPtr* start, _Out_ CharPtr* end)
|
67 mike 1.1 {
68 char* p = *pOut;
69
70 /* Skip leading whitespace */
|
71 krisbash 1.3 while (*p && isspace((unsigned char)(*p)))
|
72 mike 1.1 p++;
73
74 /* Set start of identifier */
75 *start = p;
76
77 /* Expect [A-Za-z_] characters */
78 if (!isalpha((unsigned char)(*p)) && *p != '_')
79 return -1;
80
81 /* Skip [A-Za-z_0-9] characters */
|
82 krisbash 1.3 while (*p && (isalnum((unsigned char)(*p)) || *p == '_' || *p == ':'))
|
83 mike 1.1 p++;
84
85 /* Set end of identifier */
86 *end = p;
87
88 *pOut = p;
89 return 0;
90 }
91
|
92 krisbash 1.3 _Return_type_success_(return == 0)
93 static int _ExpectChar(_Inout_ CharPtr* pOut, char ch)
|
94 mike 1.1 {
95 char* p = *pOut;
96
97 /* Skip whitespace */
|
98 krisbash 1.3 while (*p && isspace((unsigned char)(*p)))
|
99 mike 1.1 p++;
100
101 /* Expect character */
102 if (*p != ch)
103 return -1;
104 p++;
105
106 *pOut = p;
107 return 0;
108 }
109
110 // Parse a line of the form 'KEY=VALUE'
|
111 krisbash 1.3 _Return_type_success_(return == 0)
112 static int _ParseKeyValueLine(_Inout_ CharPtr* pOut, _Out_ CharPtr* keyOut, _Out_ CharPtr* valueOut)
|
113 mike 1.1 {
114 char* p = *pOut;
115 char* keyEnd;
116
117 /* Parse key */
118 if (_ParseIdentifier(&p, keyOut, &keyEnd) != 0)
119 return-1;
120
121 /* If out of input, error out */
122 if (!*p)
123 return -1;
124
125 /* Skip whitespace */
126 if (_ExpectChar(&p, '=') != 0)
127 return -1;
128
129 /* Null-terminate the key */
130 *keyEnd = '\0';
131
132 /* Skip whitespace */
|
133 krisbash 1.3 while (*p && isspace((unsigned char)(*p)))
|
134 mike 1.1 p++;
135
136 /* Set value */
137 *valueOut = p;
138
139 *pOut = p;
140 return 0;
141 }
142
|
143 krisbash 1.3 /*
144 * Parses <value> from `*CLASS=<value>` of the forms from .reg file:
145 * 1. `<ClassPath>` (Non-Association class)
146 * 2. `<ClassPath>{<ClassPath>,<ClassPath>}` (Association class)
147 */
148 _Return_type_success_(return == 0)
|
149 mike 1.1 static int _ParseClassValue(
|
150 krisbash 1.3 _Inout_ CharPtr* pOut,
151 _Out_ CharPtr* nameOut,
152 _Out_ CharPtr* refName1Out,
153 _Out_ CharPtr* refName2Out)
|
154 mike 1.1 {
155 char* p = *pOut;
156 char* start;
157 char* end;
158
159 /* Expect class name */
160 if (_ParseClassPath(&p, &start, &end) != 0)
161 return -1;
162
163 /* Skip whitespace */
|
164 krisbash 1.3 while (*p && isspace((unsigned char)(*p)))
|
165 mike 1.1 p++;
166
167 /* If end of line */
168 if (!*p)
169 {
170 *nameOut = start;
171 *end = '\0';
172 *refName1Out = NULL;
173 *refName2Out = NULL;
174 *pOut = p;
175 return 0;
176 }
177
178 /* Expect '{' character */
179 if (_ExpectChar(&p, '{') != 0)
180 return -1;
181
182 /* Get 'name' */
183 *nameOut = start;
184 *end = '\0';
185
186 mike 1.1 /* Expect reference name */
187 if (_ParseClassPath(&p, &start, &end) != 0)
188 return -1;
189
190 /* Expect ',' character */
191 if (_ExpectChar(&p, ',') != 0)
192 return -1;
193
194 /* Get 'refName1' */
195 *refName1Out = start;
196 *end = '\0';
197
198 /* Expect reference name */
199 if (_ParseClassPath(&p, &start, &end) != 0)
200 return -1;
201
202 /* Expect '}' character */
203 if (_ExpectChar(&p, '}') != 0)
204 return -1;
205
206 /* Get 'refName1' */
207 mike 1.1 *refName2Out = start;
208 *end = '\0';
209
210 *pOut = p;
211 return 0;
212 }
213
|
214 krisbash 1.3
215
216 /* Parse indication class from reg file */
217 _Return_type_success_(return == 0)
218 int ParseIndicationClass(
219 _Inout_ CharPtr* pOut,
220 _Inout_ RegFile* self,
221 _In_opt_z_ char* hosting,
222 _In_ ProvRegType type)
223 {
224 #ifdef DISABLE_INDICATION
225 /* Ignore indication classes */
226 MI_UNUSED(pOut);
227 MI_UNUSED(self);
228 MI_UNUSED(hosting);
229 MI_UNUSED(type);
230 return 0;
231 #else /* ifndef DISABLE_INDICATION */
232 char* name = NULL;
233 char* refName1 = NULL;
234 char* refName2 = NULL;
235 krisbash 1.3 RegClass* rc;
236
237 if (_ParseClassValue(pOut, &name, &refName1, &refName2) != 0)
238 {
239 trace_RegFile_ParseIndication_ClassValueFailed();
240 return -1;
241 }
242
243 rc = (RegClass*)PAL_Calloc(1, sizeof(RegClass));
244 if (!rc)
245 {
246 trace_RegFile_AllocFailure();
247 return -1;
248 }
249
250 List_Append(
251 (ListElem**)&self->classesHead,
252 (ListElem**)&self->classesTail,
253 (ListElem*)rc);
254
255 if (refName1 || refName2)
256 krisbash 1.3 {
257 trace_RegFile_IndicationClassCannotHaveRefClass();
258 return -1;
259 }
260
261 rc->name = PAL_Strdup(name);
262 if (!rc->name)
263 {
264 trace_RegFile_OutOfMemory_Name();
265 return -1;
266 }
267
268 if (hosting)
269 {
270 rc->hosting = PAL_Strdup(hosting);
271 if(!rc->hosting)
272 {
273 trace_RegFile_OutOfMemory_Hosting();
274 return -1;
275 }
276 }
277 krisbash 1.3 rc->regtype = type;
278 return 0;
279 #endif /* ifndef DISABLE_INDICATION */
280 }
281
282
|
283 mike 1.1 RegFile* RegFile_New(const char* path)
284 {
285 FILE* is;
|
286 krisbash 1.3 char buf[MAX_LINE];
|
287 mike 1.1 int foundLibrary = 0;
288 char* hosting = NULL;
289 RegFile* self = 0;
290
291 /* Open the file */
|
292 krisbash 1.3 is = File_Open(path, "rb");
|
293 mike 1.1 if (!is)
294 return NULL;
295
296 /* Allocate self structure */
|
297 krisbash 1.3 self = (RegFile*)PAL_Calloc(1, sizeof(RegFile));
|
298 mike 1.1 if (!self)
299 {
300 fclose(is);
301 return NULL;
302 }
303
304 /* Read line by line */
305 while (fgets(buf, sizeof(buf), is) != NULL)
306 {
307 char* start = buf;
308 char* p = start;
309 char* key;
310 char* value;
311
|
312 krisbash 1.3 /* Skip leading whitespace */
313 while (*p && isspace((unsigned char)(*p)))
314 p++;
315
|
316 mike 1.1 /* Skip comment lines */
317 if (*p == '#')
318 continue;
319
320 /* Remove trailing whitespace */
321 {
322 char* end = buf + strlen(buf);
323
324 while (end != start && isspace((unsigned char)end[-1]))
325 *--end = '\0';
326 }
|
327 krisbash 1.3
|
328 mike 1.1 /* Skip blank lines */
329 if (*p == '\0')
330 continue;
331
332 /* Look for LIBRARY= */
333 if (_ParseKeyValueLine(&p, &key, &value) != 0)
334 goto failed;
335
336 if (strcmp(key, "LIBRARY") == 0)
337 {
338 if (foundLibrary)
339 goto failed;
340
|
341 krisbash 1.3 self->library = PAL_Strdup(value);
|
342 mike 1.1
343 if (!self->library)
344 goto failed;
345
346 foundLibrary = 1;
347 }
348 else if (strcmp(key, "HOSTING") == 0)
349 {
350 if (hosting)
|
351 krisbash 1.3 PAL_Free(hosting);
|
352 mike 1.1
|
353 krisbash 1.3 hosting = PAL_Strdup(value);
|
354 mike 1.1 }
|
355 krisbash 1.3 else if (strcmp(key, "INSTANCELIFETIME") == 0)
356 {
357 if (strcmp(value, "CONTEXT") == 0)
358 {
359 self->instanceLifetimeContext = 1;
360 }
361 else
362 {
363 goto failed;
364 }
365 }
366 #if defined(CONFIG_ENABLE_PREEXEC)
367 else if (strcmp(key, "PREEXEC") == 0)
368 {
369 self->preexec = PAL_Strdup(value);
370 }
371 #endif /* defined(CONFIG_ENABLE_PREEXEC) */
|
372 mike 1.1 else if (strcmp(key, "CLASS") == 0)
373 {
374 char* name;
375 char* refName1;
376 char* refName2;
377 RegClass* rc;
378
379 if (_ParseClassValue(&p, &name, &refName1, &refName2) != 0)
380 goto failed;
381
|
382 krisbash 1.3 rc = (RegClass*)PAL_Calloc(1, sizeof(RegClass));
|
383 mike 1.1 if (!rc)
384 goto failed;
385
386 List_Append(
387 (ListElem**)&self->classesHead,
388 (ListElem**)&self->classesTail,
389 (ListElem*)rc);
390
|
391 krisbash 1.3 rc->name = PAL_Strdup(name);
|
392 mike 1.1 if (!rc->name)
393 goto failed;
394
395 if (refName1)
396 {
|
397 krisbash 1.3 rc->refName1 = PAL_Strdup(refName1);
|
398 mike 1.1 if (!rc->refName1)
399 goto failed;
400 }
401
402 if (refName2)
403 {
|
404 krisbash 1.3 rc->refName2 = PAL_Strdup(refName2);
|
405 mike 1.1 if (!rc->refName2)
406 goto failed;
407 }
408
409 if (hosting)
|
410 krisbash 1.3 {
411 rc->hosting = PAL_Strdup(hosting);
412 if(!rc->hosting)
413 goto failed;
414 }
415 }
416 else if (strcmp(key, "EXTRACLASS") == 0)
417 {
418 char* name;
419 char* refName1;
420 char* refName2;
421 RegClass* rc;
422
423 if (_ParseClassValue(&p, &name, &refName1, &refName2) != 0)
424 goto failed;
425
426 rc = (RegClass*)PAL_Calloc(1, sizeof(RegClass));
427 if (!rc)
428 goto failed;
429
430 List_Append(
431 krisbash 1.3 (ListElem**)&self->extraClassesHead,
432 (ListElem**)&self->extraClassesTail,
433 (ListElem*)rc);
434
435 rc->name = PAL_Strdup(name);
436 if (!rc->name)
437 goto failed;
438
439 /* no need to use refName1, refName2 as the definition of these classes will be present as part of CLASSES list or EXTRACLASSES list */
440
441 if (hosting)
442 {
443 rc->hosting = PAL_Strdup(hosting);
444 if(!rc->hosting)
445 goto failed;
446 }
447 }
448 else if (strcmp(key, REG_INDICATION_CLASS) == 0)
449 {
450 int r = ParseIndicationClass(&p, self, hosting, PROVREG_INDICATION);
451 if (r == -1)
452 krisbash 1.3 goto failed;
|
453 mike 1.1 }
454 }
455
456 if (hosting)
|
457 krisbash 1.3 PAL_Free(hosting);
458
459 /*If LIBRARY was not found (That should NOT happen),
460 which means that this regfile is corrupted (The user might have modified it by hand). So go to failed*/
461 if(!foundLibrary)
462 {
463 trace_RegFile_MissingLibraryTag(path);
464 goto failed;
465 }
|
466 mike 1.1
467 fclose(is);
468
469 return self;
470
471 failed:
472 if (self)
473 RegFile_Delete(self);
474
475 if (is)
476 fclose(is);
477
478 return NULL;
479 }
480
|
481 krisbash 1.3 static void _RegClassList_Delete(RegClass *regClassHead)
|
482 mike 1.1 {
483 RegClass* rc;
484 RegClass* next;
|
485 krisbash 1.3
486 for(rc = regClassHead; rc; rc = next)
487 {
488 if (rc->name)
489 PAL_Free(rc->name);
490
491 if (rc->refName1)
492 PAL_Free(rc->refName1);
493
494 if (rc->refName2)
495 PAL_Free(rc->refName2);
496
497 if (rc->hosting)
498 PAL_Free(rc->hosting);
499
500 next = rc->next;
501 PAL_Free(rc);
502 }
503 }
|
504 mike 1.1
|
505 krisbash 1.3 void RegFile_Delete(RegFile* self)
506 {
|
507 mike 1.1 if (!self)
508 return;
509
510 if (self->library)
|
511 krisbash 1.3 PAL_Free(self->library);
|
512 mike 1.1
|
513 krisbash 1.3 #if defined(CONFIG_ENABLE_PREEXEC)
|
514 mike 1.1
|
515 krisbash 1.3 if (self->preexec)
516 PAL_Free(self->preexec);
|
517 mike 1.1
|
518 krisbash 1.3 #endif /* defined(CONFIG_ENABLE_PREEXEC) */
|
519 mike 1.1
|
520 krisbash 1.3 _RegClassList_Delete(self->classesHead);
521 _RegClassList_Delete(self->extraClassesHead);
|
522 mike 1.1
|
523 krisbash 1.3 PAL_Free(self);
|
524 mike 1.1 }
525
526 void RegFile_Print(RegFile* self, FILE* os)
527 {
528 RegClass* rc;
529
|
530 krisbash 1.3 Ftprintf(os, ZT("LIBRARY=%s\n"), scs(self->library));
531
532 #if defined(CONFIG_ENABLE_PREEXEC)
533
534 Ftprintf(os, ZT("PREEXEC=%s\n"), scs(self->preexec));
535
536 #endif /* defined(CONFIG_ENABLE_PREEXEC) */
|
537 mike 1.1
538 for (rc = self->classesHead; rc; rc = rc->next)
539 {
|
540 krisbash 1.3 Ftprintf(os, ZT("CLASS=%s"), scs(rc->name));
|
541 mike 1.1
542 if (rc->refName1 && rc->refName2)
543 {
|
544 krisbash 1.3 Ftprintf(os, ZT("{"));
545 Ftprintf(os, ZT("%s"), scs(rc->refName1));
546 Ftprintf(os, ZT(","));
547 Ftprintf(os, ZT("%s"), scs(rc->refName2));
548 Ftprintf(os, ZT("}"));
|
549 mike 1.1 }
550
|
551 krisbash 1.3 Ftprintf(os, ZT("\n"));
|
552 mike 1.1 }
553 }
|