1 /*
2 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "istgt.h"
38 #include "istgt_misc.h"
39 #include "istgt_conf.h"
40
41 //#define CF_DELIM " \t,;"
42 #define CF_DELIM " \t"
43
44 static void istgt_free_all_cf_section(CF_SECTION *sp);
45 static void istgt_free_all_cf_item(CF_ITEM *ip);
46 static void istgt_free_all_cf_value(CF_VALUE *vp);
47 static void istgt_append_cf_item(CF_SECTION *sp, CF_ITEM *ip);
48 static void istgt_append_cf_value(CF_ITEM *ip, CF_VALUE *vp);
49
50 CONFIG *
istgt_allocate_config(void)51 istgt_allocate_config(void)
52 {
53 CONFIG *cp;
54
55 cp = xmalloc(sizeof *cp);
56 memset(cp, 0, sizeof *cp);
57 cp->file = NULL;
58 cp->section = NULL;
59
60 return cp;
61 }
62
63 void
istgt_free_config(CONFIG * cp)64 istgt_free_config(CONFIG *cp)
65 {
66 if (cp == NULL)
67 return;
68 if (cp->section != NULL) {
69 istgt_free_all_cf_section(cp->section);
70 }
71 xfree(cp->file);
72 xfree(cp);
73 }
74
75 static CF_SECTION *
istgt_allocate_cf_section(void)76 istgt_allocate_cf_section(void)
77 {
78 CF_SECTION *sp;
79
80 sp = xmalloc(sizeof *sp);
81 memset(sp, 0, sizeof *sp);
82 sp->next = NULL;
83 sp->item = NULL;
84
85 return sp;
86 }
87
88 static void
istgt_free_cf_section(CF_SECTION * sp)89 istgt_free_cf_section(CF_SECTION *sp)
90 {
91 if (sp == NULL)
92 return;
93 if (sp->item) {
94 istgt_free_all_cf_item(sp->item);
95 }
96 xfree(sp->name);
97 xfree(sp);
98 }
99
100 static void
istgt_free_all_cf_section(CF_SECTION * sp)101 istgt_free_all_cf_section(CF_SECTION *sp)
102 {
103 CF_SECTION *next;
104
105 if (sp == NULL)
106 return;
107 while (sp != NULL) {
108 next = sp->next;
109 istgt_free_cf_section(sp);
110 sp = next;
111 }
112 }
113
114 static CF_ITEM *
istgt_allocate_cf_item(void)115 istgt_allocate_cf_item(void)
116 {
117 CF_ITEM *ip;
118
119 ip = xmalloc(sizeof *ip);
120 memset(ip, 0, sizeof *ip);
121 ip->next = NULL;
122 ip->key = NULL;
123 ip->val = NULL;
124
125 return ip;
126 }
127
128 static void
istgt_free_cf_item(CF_ITEM * ip)129 istgt_free_cf_item(CF_ITEM *ip)
130 {
131 if (ip == NULL)
132 return;
133 if (ip->val != NULL) {
134 istgt_free_all_cf_value(ip->val);
135 }
136 xfree(ip->key);
137 xfree(ip);
138 }
139
140 static void
istgt_free_all_cf_item(CF_ITEM * ip)141 istgt_free_all_cf_item(CF_ITEM *ip)
142 {
143 CF_ITEM *next;
144
145 if (ip == NULL)
146 return;
147 while (ip != NULL) {
148 next = ip->next;
149 istgt_free_cf_item(ip);
150 ip = next;
151 }
152 }
153
154 static CF_VALUE *
istgt_allocate_cf_value(void)155 istgt_allocate_cf_value(void)
156 {
157 CF_VALUE *vp;
158
159 vp = xmalloc(sizeof *vp);
160 memset(vp, 0, sizeof *vp);
161 vp->next = NULL;
162 vp->value = NULL;
163
164 return vp;
165 }
166
167 static void
istgt_free_cf_value(CF_VALUE * vp)168 istgt_free_cf_value(CF_VALUE *vp)
169 {
170 if (vp == NULL)
171 return;
172 xfree(vp->value);
173 xfree(vp);
174 }
175
176 static void
istgt_free_all_cf_value(CF_VALUE * vp)177 istgt_free_all_cf_value(CF_VALUE *vp)
178 {
179 CF_VALUE *next;
180
181 if (vp == NULL)
182 return;
183 while (vp != NULL) {
184 next = vp->next;
185 istgt_free_cf_value(vp);
186 vp = next;
187 }
188 }
189
190 void
istgt_copy_cf_item(CF_SECTION * sp_dst,CF_SECTION * sp_src)191 istgt_copy_cf_item(CF_SECTION *sp_dst, CF_SECTION *sp_src)
192 {
193 CF_ITEM *ip, *ip_old;
194 CF_VALUE *vp, *vp_old;
195
196 istgt_free_all_cf_item(sp_dst->item);
197 sp_dst->item = NULL;
198
199 ip_old = sp_src->item;
200 while (ip_old != NULL) {
201 ip = istgt_allocate_cf_item();
202 istgt_append_cf_item(sp_dst, ip);
203 ip->key = xstrdup(ip_old->key);
204 ip->val = NULL;
205
206 vp_old = ip_old->val;
207 while (vp_old != NULL) {
208 vp = istgt_allocate_cf_value();
209 istgt_append_cf_value(ip, vp);
210 vp->value = xstrdup(vp_old->value);
211
212 vp_old = vp_old->next;
213 }
214 ip_old = ip_old->next;
215 }
216 }
217
218 CF_SECTION *
istgt_find_cf_section(CONFIG * cp,const char * name)219 istgt_find_cf_section(CONFIG *cp, const char *name)
220 {
221 CF_SECTION *sp;
222
223 if (name == NULL || name[0] == '\0')
224 return NULL;
225
226 for (sp = cp->section; sp != NULL; sp = sp->next) {
227 if (sp->name != NULL && sp->name[0] == name[0]
228 && strcasecmp(sp->name, name) == 0) {
229 return sp;
230 }
231 }
232
233 return NULL;
234 }
235
236 static void
istgt_append_cf_section(CONFIG * cp,CF_SECTION * sp)237 istgt_append_cf_section(CONFIG *cp, CF_SECTION *sp)
238 {
239 CF_SECTION *last;
240
241 if (cp == NULL)
242 return;
243 if (cp->section == NULL) {
244 cp->section = sp;
245 return;
246 }
247 for (last = cp->section; last->next != NULL; last = last->next)
248 ;
249 last->next = sp;
250 }
251
252 CF_ITEM *
istgt_find_cf_nitem(CF_SECTION * sp,const char * key,int idx)253 istgt_find_cf_nitem(CF_SECTION *sp, const char *key, int idx)
254 {
255 CF_ITEM *ip;
256 int i;
257
258 if (key == NULL || key[0] == '\0')
259 return NULL;
260
261 i = 0;
262 for (ip = sp->item; ip != NULL; ip = ip->next) {
263 if (ip->key != NULL && ip->key[0] == key[0]
264 && strcasecmp(ip->key, key) == 0) {
265 if (i == idx) {
266 return ip;
267 }
268 i++;
269 }
270 }
271
272 return NULL;
273 }
274
275 CF_ITEM *
istgt_find_cf_item(CF_SECTION * sp,const char * key)276 istgt_find_cf_item(CF_SECTION *sp, const char *key)
277 {
278 return istgt_find_cf_nitem(sp, key, 0);
279 }
280
281 static void
istgt_append_cf_item(CF_SECTION * sp,CF_ITEM * ip)282 istgt_append_cf_item(CF_SECTION *sp, CF_ITEM *ip)
283 {
284 CF_ITEM *last;
285
286 if (sp == NULL)
287 return;
288 if (sp->item == NULL) {
289 sp->item = ip;
290 return;
291 }
292 for (last = sp->item; last->next != NULL; last = last->next)
293 ;
294 last->next = ip;
295 }
296
297 static void
istgt_append_cf_value(CF_ITEM * ip,CF_VALUE * vp)298 istgt_append_cf_value(CF_ITEM *ip, CF_VALUE *vp)
299 {
300 CF_VALUE *last;
301
302 if (ip == NULL)
303 return;
304 if (ip->val == NULL) {
305 ip->val = vp;
306 return;
307 }
308 for (last = ip->val; last->next != NULL; last = last->next)
309 ;
310 last->next = vp;
311 }
312
313 static void
istgt_set_cf_section_type(CF_SECTION * sp)314 istgt_set_cf_section_type(CF_SECTION *sp)
315 {
316 static struct cfst_table_t {
317 const char *name;
318 CF_SECTION_TYPE type;
319 } cfst_table[] = {
320 { "Global", ST_GLOBAL },
321 { "UnitControl", ST_UNITCONTROL },
322 { "PortalGroup", ST_PORTALGROUP },
323 { "InitiatorGroup", ST_INITIATORGROUP },
324 { "LogicalUnit", ST_LOGICAL_UNIT },
325 { "AuthGroup", ST_AUTHGROUP },
326 { NULL, ST_INVALID },
327 };
328 int i;
329
330 if (sp == NULL || sp->name == NULL)
331 return;
332 for (i = 0; cfst_table[i].name != NULL; i++) {
333 if (sp->name[0] == cfst_table[i].name[0]
334 && strncasecmp(sp->name, cfst_table[i].name,
335 strlen(cfst_table[i].name)) == 0) {
336 sp->type = cfst_table[i].type;
337 return;
338 }
339 }
340 sp->type = ST_NONE;
341 }
342
343 static int
parse_line(CONFIG * cp,char * lp)344 parse_line(CONFIG *cp, char *lp)
345 {
346 CF_SECTION *sp;
347 CF_ITEM *ip;
348 CF_VALUE *vp;
349 char *arg;
350 char *key;
351 char *val;
352 char *p;
353 int num;
354
355 arg = trim_string(lp);
356 if (arg[0] == '[') {
357 /* section */
358 arg++;
359 key = strsepq(&arg, "]");
360 if (key == NULL || arg != NULL) {
361 fprintf(stderr, "broken section\n");
362 return -1;
363 }
364 /* determine section number */
365 for (p = key; *p != '\0' && !isdigit((int) *p); p++)
366 ;
367 if (*p != '\0') {
368 num = (int)strtol(p, NULL, 10);
369 } else {
370 num = 0;
371 }
372
373 sp = istgt_find_cf_section(cp, key);
374 if (sp == NULL) {
375 sp = istgt_allocate_cf_section();
376 istgt_append_cf_section(cp, sp);
377 }
378 cp->current_section = sp;
379 sp->name = xstrdup(key);
380 sp->num = num;
381 istgt_set_cf_section_type(sp);
382 } else {
383 /* parameters */
384 sp = cp->current_section;
385 if (sp == NULL) {
386 fprintf(stderr, "unknown section\n");
387 return -1;
388 }
389 key = strsepq(&arg, CF_DELIM);
390 if (key == NULL) {
391 fprintf(stderr, "broken key\n");
392 return -1;
393 }
394
395 ip = istgt_allocate_cf_item();
396 istgt_append_cf_item(sp, ip);
397 ip->key = xstrdup(key);
398 ip->val = NULL;
399 if (arg != NULL) {
400 /* key has value(s) */
401 while (arg != NULL) {
402 val = strsepq(&arg, CF_DELIM);
403 vp = istgt_allocate_cf_value();
404 istgt_append_cf_value(ip, vp);
405 vp->value = xstrdup(val);
406 }
407 }
408 }
409
410 return 0;
411 }
412
413 static char *
fgets_line(FILE * fp)414 fgets_line (FILE *fp)
415 {
416 char *dst, *p;
417 size_t total, len;
418
419 dst = p = xmalloc(MAX_TMPBUF);
420 dst[0] = '\0';
421 total = 0;
422
423 while (fgets(p, MAX_TMPBUF, fp) != NULL) {
424 len = strlen(p);
425 total += len;
426 if (len + 1 < MAX_TMPBUF || dst[total - 1] == '\n') {
427 return xrealloc(dst, total + 1);
428 }
429 dst = xrealloc (dst, total + MAX_TMPBUF);
430 p = dst + total;
431 }
432
433 if (feof(fp) && total != 0) {
434 dst = xrealloc(dst, total + 2);
435 dst[total] = '\n';
436 dst[total + 1] = '\0';
437 return dst;
438 }
439
440 xfree(dst);
441
442 return NULL;
443 }
444
445 int
istgt_read_config(CONFIG * cp,const char * file)446 istgt_read_config(CONFIG *cp, const char *file)
447 {
448 FILE *fp;
449 char *lp, *p;
450 char *lp2, *q;
451 int line;
452 int n, n2;
453
454 if (file == NULL || file[0] == '\0')
455 return -1;
456 fp = fopen(file, "r");
457 if (fp == NULL) {
458 fprintf(stderr, "open error: %s\n", file);
459 return -1;
460 }
461 cp->file = xstrdup(file);
462
463 line = 1;
464 while ((lp = fgets_line(fp)) != NULL) {
465 /* skip spaces */
466 for (p = lp; *p != '\0' && isspace((int) *p); p++)
467 ;
468 /* skip comment, empty line */
469 if (p[0] == '#' || p[0] == '\0')
470 goto next_line;
471
472 /* concatenate line end with '\' */
473 n = strlen(p);
474 while (n > 2 && p[n - 1] == '\n' && p[n - 2] == '\\') {
475 n -= 2;
476 lp2 = fgets_line(fp);
477 if (lp2 == NULL)
478 break;
479 line++;
480 n2 = strlen(lp2);
481 q = xmalloc(n + n2 + 1);
482 memcpy(q, p, n);
483 memcpy(q + n, lp2, n2);
484 q[n + n2] = '\0';
485 xfree(lp2);
486 xfree(lp);
487 p = lp = q;
488 n += n2;
489 }
490
491 /* parse one line */
492 if (parse_line(cp, p) < 0) {
493 fprintf(stderr, "parse error at line %d of %s\n", line, cp->file);
494 }
495 next_line:
496 line++;
497 xfree(lp);
498 }
499
500 fclose(fp);
501 return 0;
502 }
503
504 int
istgt_print_config(CONFIG * cp)505 istgt_print_config(CONFIG *cp)
506 {
507 CF_SECTION *sp;
508 CF_ITEM *ip;
509 CF_VALUE *vp;
510
511 if (cp == NULL)
512 return -1;
513
514 /* empty config? */
515 sp = cp->section;
516 if (sp == NULL)
517 return 0;
518
519 while (sp != NULL) {
520 printf("Section: %s\n", sp->name);
521 ip = sp->item;
522 while (ip != NULL) {
523 printf(" Item: %s ", ip->key);
524 vp = ip->val;
525 while (vp != NULL) {
526 printf("Val: %s ", vp->value);
527 vp = vp->next;
528 }
529 printf("\n");
530 ip = ip->next;
531 }
532 sp = sp->next;
533 }
534
535 return 0;
536 }
537