]> git.proxmox.com Git - mirror_corosync.git/blob - exec/coroparse.c
convert readdir into readdir_r
[mirror_corosync.git] / exec / coroparse.c
1 /*
2 * Copyright (c) 2006, 2009 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Patrick Caulfield (pcaulfie@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the MontaVista Software, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <config.h>
36
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/un.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <dirent.h>
51 #include <limits.h>
52 #include <stddef.h>
53
54 #include <corosync/lcr/lcr_comp.h>
55 #include <corosync/engine/objdb.h>
56 #include <corosync/engine/config.h>
57
58 #include "util.h"
59
60 static int read_config_file_into_objdb(
61 struct objdb_iface_ver0 *objdb,
62 const char **error_string);
63 static char error_string_response[512];
64
65
66 static char *strchr_rs (const char *haystack, int byte)
67 {
68 const char *end_address = strchr (haystack, byte);
69 if (end_address) {
70 end_address += 1; /* skip past { or = */
71 end_address += strspn (end_address, " \t");
72 }
73
74 return ((char *) end_address);
75 }
76
77 static int aisparser_readconfig (struct objdb_iface_ver0 *objdb,
78 const char **error_string)
79 {
80 if (read_config_file_into_objdb(objdb, error_string)) {
81 return -1;
82 }
83
84 return 0;
85 }
86
87
88 static char *remove_whitespace(char *string)
89 {
90 char *start = string+strspn(string, " \t");
91 char *end = start+(strlen(start))-1;
92
93 while ((*end == ' ' || *end == '\t' || *end == ':' || *end == '{') && end > start)
94 end--;
95 if (end != start)
96 *(end+1) = '\0';
97
98 return start;
99 }
100
101 #define PCHECK_ADD_SUBSECTION 1
102 #define PCHECK_ADD_ITEM 2
103
104 typedef int (*parser_check_item_f)(struct objdb_iface_ver0 *objdb,
105 hdb_handle_t parent_handle,
106 int type,
107 const char *name,
108 const char **error_string);
109
110 static int parse_section(FILE *fp,
111 struct objdb_iface_ver0 *objdb,
112 hdb_handle_t parent_handle,
113 const char **error_string,
114 parser_check_item_f parser_check_item_call)
115 {
116 char line[512];
117 int i;
118 char *loc;
119 int ignore_line;
120
121 while (fgets (line, sizeof (line), fp)) {
122 if (strlen(line) > 0) {
123 if (line[strlen(line) - 1] == '\n')
124 line[strlen(line) - 1] = '\0';
125 if (strlen (line) > 0 && line[strlen(line) - 1] == '\r')
126 line[strlen(line) - 1] = '\0';
127 }
128 /*
129 * Clear out white space and tabs
130 */
131 for (i = strlen (line) - 1; i > -1; i--) {
132 if (line[i] == '\t' || line[i] == ' ') {
133 line[i] = '\0';
134 } else {
135 break;
136 }
137 }
138
139 ignore_line = 1;
140 for (i = 0; i < strlen (line); i++) {
141 if (line[i] != '\t' && line[i] != ' ') {
142 if (line[i] != '#')
143 ignore_line = 0;
144
145 break;
146 }
147 }
148 /*
149 * Clear out comments and empty lines
150 */
151 if (ignore_line) {
152 continue;
153 }
154
155 /* New section ? */
156 if ((loc = strchr_rs (line, '{'))) {
157 hdb_handle_t new_parent;
158 char *section = remove_whitespace(line);
159
160 loc--;
161 *loc = '\0';
162 if (parser_check_item_call) {
163 if (!parser_check_item_call(objdb, parent_handle, PCHECK_ADD_SUBSECTION,
164 section, error_string))
165 return -1;
166 }
167
168 objdb->object_create (parent_handle, &new_parent,
169 section, strlen (section));
170 if (parse_section(fp, objdb, new_parent, error_string, parser_check_item_call))
171 return -1;
172 }
173
174 /* New key/value */
175 if ((loc = strchr_rs (line, ':'))) {
176 char *key;
177 char *value;
178
179 *(loc-1) = '\0';
180 key = remove_whitespace(line);
181 value = remove_whitespace(loc);
182 if (parser_check_item_call) {
183 if (!parser_check_item_call(objdb, parent_handle, PCHECK_ADD_ITEM,
184 key, error_string))
185 return -1;
186 }
187 objdb->object_key_create_typed (parent_handle, key,
188 value, strlen (value) + 1, OBJDB_VALUETYPE_STRING);
189 }
190
191 if ((loc = strchr_rs (line, '}'))) {
192 return 0;
193 }
194 }
195
196 if (parent_handle != OBJECT_PARENT_HANDLE) {
197 *error_string = "Missing closing brace";
198 return -1;
199 }
200
201 return 0;
202 }
203
204 static int parser_check_item_uidgid(struct objdb_iface_ver0 *objdb,
205 hdb_handle_t parent_handle,
206 int type,
207 const char *name,
208 const char **error_string)
209 {
210 if (type == PCHECK_ADD_SUBSECTION) {
211 if (parent_handle != OBJECT_PARENT_HANDLE) {
212 *error_string = "uidgid: Can't add second level subsection";
213 return 0;
214 }
215
216 if (strcmp (name, "uidgid") != 0) {
217 *error_string = "uidgid: Can't add subsection different then uidgid";
218 return 0;
219 }
220 }
221
222 if (type == PCHECK_ADD_ITEM) {
223 if (!(strcmp (name, "uid") == 0 || strcmp (name, "gid") == 0)) {
224 *error_string = "uidgid: Only uid and gid are allowed items";
225 return 0;
226 }
227 }
228
229 return 1;
230 }
231
232 static int parser_check_item_service(struct objdb_iface_ver0 *objdb,
233 hdb_handle_t parent_handle,
234 int type,
235 const char *name,
236 const char **error_string)
237 {
238 if (type == PCHECK_ADD_SUBSECTION) {
239 if (parent_handle != OBJECT_PARENT_HANDLE) {
240 *error_string = "service: Can't add second level subsection";
241 return 0;
242 }
243
244 if (strcmp (name, "service") != 0) {
245 *error_string = "service: Can't add subsection different then service";
246 return 0;
247 }
248 }
249
250 if (type == PCHECK_ADD_ITEM) {
251 if (!(strcmp (name, "name") == 0 || strcmp (name, "ver") == 0)) {
252 *error_string = "service: Only name and ver are allowed items";
253 return 0;
254 }
255 }
256
257 return 1;
258 }
259
260 static int read_uidgid_files_into_objdb(
261 struct objdb_iface_ver0 *objdb,
262 const char **error_string)
263 {
264 FILE *fp;
265 const char *dirname;
266 DIR *dp;
267 struct dirent *dirent;
268 struct dirent *entry;
269 char filename[PATH_MAX + FILENAME_MAX + 1];
270 int res = 0;
271 size_t len;
272 int return_code;
273 struct stat stat_buf;
274
275 dirname = COROSYSCONFDIR "/uidgid.d";
276 dp = opendir (dirname);
277
278 if (dp == NULL)
279 return 0;
280
281 len = offsetof(struct dirent, d_name) +
282 pathconf(dirname, _PC_NAME_MAX) + 1;
283 entry = malloc(len);
284
285 for (return_code = readdir_r(dp, entry, &dirent);
286 dirent != NULL && return_code == 0;
287 return_code = readdir_r(dp, entry, &dirent)) {
288
289 snprintf(filename, sizeof (filename), "%s/%s", dirname, dirent->d_name);
290 stat (filename, &stat_buf);
291 if (S_ISREG(stat_buf.st_mode)) {
292
293 fp = fopen (filename, "r");
294 if (fp == NULL) continue;
295
296 res = parse_section(fp, objdb, OBJECT_PARENT_HANDLE, error_string, parser_check_item_uidgid);
297
298 fclose (fp);
299
300 if (res != 0) {
301 goto error_exit;
302 }
303 }
304 }
305
306 error_exit:
307 free (entry);
308 closedir(dp);
309
310 return res;
311 }
312
313 static int read_service_files_into_objdb(
314 struct objdb_iface_ver0 *objdb,
315 const char **error_string)
316 {
317 FILE *fp;
318 const char *dirname;
319 DIR *dp;
320 struct dirent *dirent;
321 struct dirent *entry;
322 char filename[PATH_MAX + FILENAME_MAX + 1];
323 int res = 0;
324 struct stat stat_buf;
325 size_t len;
326 int return_code;
327
328 dirname = COROSYSCONFDIR "/service.d";
329 dp = opendir (dirname);
330
331 if (dp == NULL)
332 return 0;
333
334 len = offsetof(struct dirent, d_name) +
335 pathconf(dirname, _PC_NAME_MAX) + 1;
336 entry = malloc(len);
337
338 for (return_code = readdir_r(dp, entry, &dirent);
339 dirent != NULL && return_code == 0;
340 return_code = readdir_r(dp, entry, &dirent)) {
341
342 snprintf(filename, sizeof (filename), "%s/%s", dirname, dirent->d_name);
343 stat (filename, &stat_buf);
344 if (S_ISREG(stat_buf.st_mode)) {
345
346 fp = fopen (filename, "r");
347 if (fp == NULL) continue;
348
349 res = parse_section(fp, objdb, OBJECT_PARENT_HANDLE, error_string, parser_check_item_service);
350
351 fclose (fp);
352
353 if (res != 0) {
354 goto error_exit;
355 }
356 }
357 }
358
359 error_exit:
360 free (entry);
361 closedir(dp);
362
363 return res;
364 }
365
366 /* Read config file and load into objdb */
367 static int read_config_file_into_objdb(
368 struct objdb_iface_ver0 *objdb,
369 const char **error_string)
370 {
371 FILE *fp;
372 const char *filename;
373 char *error_reason = error_string_response;
374 int res;
375
376 filename = getenv ("COROSYNC_MAIN_CONFIG_FILE");
377 if (!filename)
378 filename = COROSYSCONFDIR "/corosync.conf";
379
380 fp = fopen (filename, "r");
381 if (fp == NULL) {
382 snprintf (error_reason, sizeof(error_string_response),
383 "Can't read file %s reason = (%s)\n",
384 filename, strerror (errno));
385 *error_string = error_reason;
386 return -1;
387 }
388
389 res = parse_section(fp, objdb, OBJECT_PARENT_HANDLE, error_string, NULL);
390
391 fclose(fp);
392
393 if (res == 0) {
394 res = read_uidgid_files_into_objdb(objdb, error_string);
395 }
396
397 if (res == 0) {
398 res = read_service_files_into_objdb(objdb, error_string);
399 }
400
401 if (res == 0) {
402 snprintf (error_reason, sizeof(error_string_response),
403 "Successfully read main configuration file '%s'.\n", filename);
404 *error_string = error_reason;
405 }
406
407 return res;
408 }
409
410 /*
411 * Dynamic Loader definition
412 */
413
414 struct config_iface_ver0 aisparser_iface_ver0 = {
415 .config_readconfig = aisparser_readconfig
416 };
417
418 struct lcr_iface corosync_aisparser_ver0[1] = {
419 {
420 .name = "corosync_parser",
421 .version = 0,
422 .versions_replace = 0,
423 .versions_replace_count = 0,
424 .dependencies = 0,
425 .dependency_count = 0,
426 .constructor = NULL,
427 .destructor = NULL,
428 .interfaces = NULL,
429 }
430 };
431
432 struct corosync_service_handler *aisparser_get_handler_ver0 (void);
433
434 struct lcr_comp aisparser_comp_ver0 = {
435 .iface_count = 1,
436 .ifaces = corosync_aisparser_ver0
437 };
438
439 #ifdef COROSYNC_SOLARIS
440 void corosync_lcr_component_register (void);
441
442 void corosync_lcr_component_register (void) {
443 #else
444 __attribute__ ((constructor)) static void corosync_lcr_component_register (void) {
445 #endif
446 lcr_interfaces_set (&corosync_aisparser_ver0[0], &aisparser_iface_ver0);
447 lcr_component_register (&aisparser_comp_ver0);
448 }