/[vps]/baselayout-vserver/trunk/src/core/librcscripts/parse.c
Gentoo

Contents of /baselayout-vserver/trunk/src/core/librcscripts/parse.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 127 - (show annotations) (download) (as text)
Fri Dec 2 10:56:06 2005 UTC (12 years, 8 months ago) by phreak
File MIME type: text/x-csrc
File size: 24563 byte(s)
Import the latest baselayout changes. Merging revision 1658.
1 /*
2 * parse.c
3 *
4 * Parser for Gentoo style rc-scripts.
5 *
6 * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * $Header$
23 */
24
25 #include <errno.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 #include <sys/poll.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <signal.h>
38
39 #include "rcscripts.h"
40 #include "debug.h"
41 #include "depend.h"
42 #include "list.h"
43 #include "misc.h"
44 #include "parse.h"
45 #include "simple-regex.h"
46
47 #define READ_PIPE 0
48 #define WRITE_PIPE 1
49
50 /* _pipe[0] is used to send data to the parent (thus the parent only use the
51 * read pipe, and the child uses the write pipe)
52 * _pipe[1] is used to send data to the child (thus the child only use the read
53 * pipe, and the parent uses the write pipe)
54 */
55 #define PARENT_READ_PIPE(_pipe) (_pipe[0][READ_PIPE])
56 #define PARENT_WRITE_PIPE(_pipe) (_pipe[1][WRITE_PIPE])
57 #define CHILD_READ_PIPE(_pipe) (_pipe[1][READ_PIPE])
58 #define CHILD_WRITE_PIPE(_pipe) (_pipe[0][WRITE_PIPE])
59
60 #define PARSE_BUFFER_SIZE 256
61
62 #define OUTPUT_MAX_LINE_LENGHT 256
63 #define OUTPUT_BUFFER_SIZE (60 * 2048)
64
65 /* void PRINT_TO_BUFFER(char **_buf, int _count, label _error, format) */
66 #define PRINT_TO_BUFFER(_buf, _count, _error, _output...) \
67 do { \
68 int _i = 0; \
69 /* FIXME: Might do something more dynamic here */ \
70 if (OUTPUT_BUFFER_SIZE < (_count + OUTPUT_MAX_LINE_LENGHT)) { \
71 errno = ENOMEM; \
72 DBG_MSG("Output buffer size too small!\n"); \
73 goto _error; \
74 } \
75 _i = sprintf(&((*_buf)[_count]), _output); \
76 if (0 < _i) \
77 _count += _i + 1; \
78 } while (0)
79
80 LIST_HEAD(rcscript_list);
81
82 size_t parse_rcscript(char *scriptname, char **data, size_t index);
83
84 size_t parse_print_start(char **data, size_t index);
85 size_t parse_print_header(char *scriptname, char **data, size_t index);
86 size_t parse_print_body(char *scriptname, char **data, size_t index);
87
88 int get_rcscripts(void)
89 {
90 rcscript_info_t *info;
91 char **file_list = NULL;
92 char *rcscript;
93 char *confd_file = NULL;
94 int count;
95
96 file_list = ls_dir(RCSCRIPTS_INITDDIR, 0);
97 if (NULL == file_list) {
98 DBG_MSG("'%s' is empty!\n", RCSCRIPTS_INITDDIR);
99 return -1;
100 }
101
102 STRING_LIST_FOR_EACH(file_list, rcscript, count) {
103 /* Is it a file? */
104 if (!(is_file(rcscript, 1))
105 /* Do not process scripts, source or backup files. */
106 || (CHECK_FILE_EXTENSION(rcscript, ".c"))
107 || (CHECK_FILE_EXTENSION(rcscript, ".bak"))
108 || (CHECK_FILE_EXTENSION(rcscript, "~"))) {
109 DBG_MSG("'%s' is not a valid rc-script!\n",
110 gbasename(rcscript));
111 } else {
112 DBG_MSG("Adding rc-script '%s' to list.\n",
113 gbasename(rcscript));
114
115 info = malloc(sizeof(rcscript_info_t));
116 if (NULL == info) {
117 DBG_MSG("Failed to allocate rcscript_info_t!\n");
118 goto error;
119 }
120
121 /* Copy the name */
122 info->filename = strndup(rcscript, strlen(rcscript));
123 if (NULL == info->filename) {
124 DBG_MSG("Failed to allocate buffer!\n");
125 goto loop_error;
126 }
127
128 /* Get the modification time */
129 info->mtime = get_mtime(rcscript, 1);
130 if (0 == info->mtime) {
131 DBG_MSG("Failed to get modification time for '%s'!\n",
132 rcscript);
133 /* We do not care if it fails - we will pick up
134 * later if there is a problem with the file */
135 }
136
137 /* File name for the conf.d config file (if any) */
138 confd_file = strcatpaths(RCSCRIPTS_CONFDDIR, gbasename(rcscript));
139 if (NULL == confd_file) {
140 DBG_MSG("Failed to allocate temporary buffer!\n");
141 goto loop_error;
142 }
143
144 /* Get the modification time of the conf.d file
145 * (if any exists) */
146 info->confd_mtime = get_mtime(confd_file, 1);
147 if (0 == info->confd_mtime) {
148 DBG_MSG("Failed to get modification time for '%s'!\n",
149 confd_file);
150 /* We do not care that it fails, as not all
151 * rc-scripts will have conf.d config files */
152 }
153
154 free(confd_file);
155
156 list_add_tail(&info->node, &rcscript_list);
157
158 continue;
159
160 loop_error:
161 if (NULL != info)
162 free(info->filename);
163 free(info);
164
165 goto error;
166 }
167 }
168
169 /* Final check if we have some entries */
170 if ((NULL == file_list) || (NULL == file_list[0])) {
171 DBG_MSG("No rc-scripts to parse!\n");
172 errno = ENOENT;
173 goto error;
174 }
175
176 STRING_LIST_FREE(file_list);
177
178 return 0;
179
180 error:
181 STRING_LIST_FREE(file_list);
182
183 return -1;
184 }
185
186 /* Returns 0 if we do not need to regen the cache file, else -1 with
187 * errno set if something went wrong */
188 int check_rcscripts_mtime(char *cachefile)
189 {
190 rcscript_info_t *info;
191 time_t cache_mtime;
192 time_t rc_conf_mtime;
193 time_t rc_confd_mtime;
194
195 if ((NULL == cachefile) || (0 == strlen(cachefile))) {
196 DBG_MSG("Invalid argument passed!\n");
197 errno = EINVAL;
198 return -1;
199 }
200
201 cache_mtime = get_mtime(cachefile, 1);
202 if (0 == cache_mtime) {
203 DBG_MSG("Could not get modification time for cache file '%s'!\n",
204 cachefile);
205 return -1;
206 }
207
208 /* Get and compare mtime for RC_CONF_FILE_NAME with that of cachefile */
209 rc_conf_mtime = get_mtime(RC_CONF_FILE_NAME, 1);
210 if (rc_conf_mtime > cache_mtime) {
211 DBG_MSG("'%s' have a later modification time than '%s'.\n",
212 RC_CONF_FILE_NAME, cachefile);
213 return -1;
214 }
215 /* Get and compare mtime for RC_CONFD_FILE_NAME with that of cachefile */
216 rc_confd_mtime = get_mtime(RC_CONFD_FILE_NAME, 1);
217 if (rc_confd_mtime > cache_mtime) {
218 DBG_MSG("'%s' have a later modification time than '%s'.\n",
219 RC_CONFD_FILE_NAME, cachefile);
220 return -1;
221 }
222
223 /* Get and compare mtime for each rc-script and its conf.d config file
224 * with that of cachefile */
225 list_for_each_entry(info, &rcscript_list, node) {
226 if ((info->mtime > cache_mtime)
227 || (info->confd_mtime > cache_mtime)) {
228 DBG_MSG("'%s' have a later modification time than '%s'.\n",
229 info->filename, cachefile);
230 return -1;
231 }
232 }
233
234 return 0;
235 }
236
237 /* Return count on success, -1 on error. If it was critical, errno will be set. */
238 size_t parse_rcscript(char *scriptname, char **data, size_t index)
239 {
240 regex_data_t tmp_data;
241 char *buf = NULL;
242 char *tmp_buf = NULL;
243 size_t write_count = index;
244 size_t lenght;
245 int count;
246 int current = 0;
247
248 if ((NULL == scriptname) || (0 == strlen(scriptname))) {
249 DBG_MSG("Invalid argument passed!\n");
250 errno = EINVAL;
251 return -1;
252 }
253
254 if (-1 == file_map(scriptname, &buf, &lenght)) {
255 DBG_MSG("Could not open '%s' for reading!\n",
256 gbasename(scriptname));
257 return -1;
258 }
259
260 while (current < lenght) {
261 count = buf_get_line(buf, lenght, current);
262
263 tmp_buf = strndup(&(buf[current]), count);
264 if (NULL == tmp_buf) {
265 DBG_MSG("Failed to allocate temporary buffer!\n");
266 goto error;
267 }
268
269 if (0 == current) {
270 /* Check if it starts with '#!/sbin/runscript' */
271 DO_REGEX(tmp_data, tmp_buf,
272 "[ \t]*#![ \t]*/sbin/runscript[ \t]*.*", error);
273 if (REGEX_FULL_MATCH != tmp_data.match) {
274 DBG_MSG("'%s' is not a valid rc-script!\n",
275 gbasename(scriptname));
276 goto error;
277 }
278
279 /* We do not want rc-scripts ending in '.sh' */
280 if (CHECK_FILE_EXTENSION(scriptname, ".sh")) {
281 EWARN("'%s' is invalid (should not end with '.sh')!\n",
282 gbasename(scriptname));
283 goto error;
284 }
285 DBG_MSG("Parsing '%s'.\n", gbasename(scriptname));
286
287 write_count = parse_print_header(gbasename(scriptname),
288 data, write_count);
289 if (-1 == write_count) {
290 DBG_MSG("Failed to call parse_print_header()!\n");
291 goto error;
292 }
293
294 goto _continue;
295 }
296
297 /* Check for lines with comments, and skip them */
298 DO_REGEX(tmp_data, tmp_buf, "^[ \t]*#", error);
299 if (REGEX_MATCH(tmp_data))
300 goto _continue;
301
302 /* If the line contains 'depend()', set 'got_depend' */
303 DO_REGEX(tmp_data, tmp_buf, "depend[ \t]*()[ \t]*{?", error);
304 if (REGEX_MATCH(tmp_data)) {
305 DBG_MSG("Got 'depend()' function.\n");
306
307 write_count = parse_print_body(gbasename(scriptname),
308 data, write_count);
309 if (-1 == write_count) {
310 DBG_MSG("Failed to call parse_print_body()!\n");
311 goto error;
312 }
313
314 /* Make sure this is the last loop */
315 current += lenght;
316 goto _continue;
317 }
318
319 _continue:
320 current += count + 1;
321 free(tmp_buf);
322 }
323
324 file_unmap(buf, lenght);
325
326 return write_count;
327
328 error:
329 free(tmp_buf);
330 if (NULL != buf) {
331 int old_errno = errno;
332 file_unmap(buf, lenght);
333 /* file_unmap() might have changed it */
334 errno = old_errno;
335 }
336
337 return -1;
338 }
339
340
341 size_t generate_stage1(char **data)
342 {
343 rcscript_info_t *info;
344 size_t write_count = 0;
345 size_t tmp_count;
346
347 write_count = parse_print_start(data, write_count);
348 if (-1 == write_count) {
349 DBG_MSG("Failed to call parse_print_start()!\n");
350 return -1;
351 }
352
353 list_for_each_entry(info, &rcscript_list, node) {
354 tmp_count = parse_rcscript(info->filename, data, write_count);
355 if (-1 == tmp_count) {
356 DBG_MSG("Failed to parse '%s'!\n",
357 gbasename(info->filename));
358
359 /* If 'errno' is set, it is critical (hopefully) */
360 if (0 != errno)
361 return -1;
362 } else {
363 write_count = tmp_count;
364 }
365 }
366
367 return write_count;
368 }
369
370 /* Empty signal handler for SIGPIPE */
371 static void sig_handler(int signum)
372 {
373 return;
374 }
375
376 /* Returns data's lenght on success, else -1 on error. */
377 size_t generate_stage2(char **data)
378 {
379 int pipe_fds[2][2] = { { 0, 0 }, { 0, 0 } };
380 pid_t child_pid;
381 size_t write_count = 0;
382 int old_errno = 0;
383
384 /* Pipe to send data to parent */
385 if (-1 == pipe(pipe_fds[0])) {
386 DBG_MSG("Failed to open pipe!\n");
387 goto error;
388 }
389 /* Pipe to send data to child */
390 if (-1 == pipe(pipe_fds[1])) {
391 DBG_MSG("Failed to open pipe!\n");
392 /* Close parent_pfds */
393 goto error;
394 }
395
396 /* Zero data */
397 *data = NULL;
398
399 child_pid = fork();
400 if (-1 == child_pid) {
401 DBG_MSG("Failed to fork()!\n");
402 /* Close all pipes */
403 goto error;
404 }
405 if (0 == child_pid) {
406 /***
407 *** In child
408 ***/
409
410 char *const argv[] = {
411 "bash",
412 "--noprofile",
413 "--norc",
414 "--",
415 NULL
416 };
417
418 /* Close the sides of the pipes we do not use */
419 close(PARENT_WRITE_PIPE(pipe_fds));
420 close(PARENT_READ_PIPE(pipe_fds));
421
422 /* dup2 child side read pipe to STDIN */
423 dup2(CHILD_READ_PIPE(pipe_fds), STDIN_FILENO);
424 /* dup2 child side write pipe to STDOUT */
425 dup2(CHILD_WRITE_PIPE(pipe_fds), STDOUT_FILENO);
426
427 /* We need to be in RCSCRIPTS_INITDDIR for 'before'/'after' '*' to work */
428 if (-1 == chdir(RCSCRIPTS_INITDDIR)) {
429 DBG_MSG("Failed to chdir to '%s'!\n", RCSCRIPTS_INITDDIR);
430 exit(1);
431 }
432
433 if (-1 == execv(SHELL_PARSER, argv)) {
434 DBG_MSG("Failed to execv %s!\n", SHELL_PARSER);
435 exit(1);
436 }
437 } else {
438 /***
439 *** In parent
440 ***/
441
442 struct sigaction act_new;
443 struct sigaction act_old;
444 struct pollfd poll_fds[2];
445 char buf[PARSE_BUFFER_SIZE+1];
446 char *stage1_data = NULL;
447 size_t stage1_write_count = 0;
448 size_t stage1_written = 0;
449 int status = 0;
450
451 DBG_MSG("Child pid = %i\n", child_pid);
452
453 /* Set signal handler for SIGPIPE to empty in case bash errors
454 * out. It will then close the write pipe, and instead of us
455 * getting SIGPIPE, we can handle the write error like normal.
456 */
457 memset(&act_new, 0x00, sizeof(act_new));
458 act_new.sa_handler = (void (*) (int))sig_handler;
459 sigemptyset (&act_new.sa_mask);
460 act_new.sa_flags = 0;
461 sigaction(SIGPIPE, &act_new, &act_old);
462
463 /* Close the sides of the pipes we do not use */
464 close(CHILD_WRITE_PIPE(pipe_fds));
465 CHILD_WRITE_PIPE(pipe_fds) = 0;
466 close(CHILD_READ_PIPE(pipe_fds));
467 CHILD_READ_PIPE(pipe_fds) = 0;
468
469 stage1_data = malloc(OUTPUT_BUFFER_SIZE + 1);
470 if (NULL == stage1_data) {
471 DBG_MSG("Failed to allocate buffer!\n");
472 goto error;
473 }
474
475 /* Pipe parse_rcscripts() to bash */
476 stage1_write_count = generate_stage1(&stage1_data);
477 if (-1 == stage1_write_count) {
478 DBG_MSG("Failed to generate stage1!\n");
479 goto error;
480 }
481
482 #if 0
483 int tmp_fd = open("bar", O_CREAT | O_TRUNC | O_RDWR, 0600);
484 write(tmp_fd, stage1_data, stage1_write_count);
485 close(tmp_fd);
486 #endif
487
488 do {
489 int tmp_count = 0;
490 int do_write = 0;
491 int do_read = 0;
492
493 /* Check if we can write or read */
494 poll_fds[WRITE_PIPE].fd = PARENT_WRITE_PIPE(pipe_fds);
495 poll_fds[WRITE_PIPE].events = POLLOUT;
496 poll_fds[READ_PIPE].fd = PARENT_READ_PIPE(pipe_fds);
497 poll_fds[READ_PIPE].events = POLLIN | POLLPRI;
498 if (stage1_written < stage1_write_count) {
499 poll(poll_fds, 2, -1);
500 if (poll_fds[WRITE_PIPE].revents & POLLOUT)
501 do_write = 1;
502 } else {
503 poll(&(poll_fds[READ_PIPE]), 1, -1);
504 }
505 if ((poll_fds[READ_PIPE].revents & POLLIN)
506 || (poll_fds[READ_PIPE].revents & POLLPRI))
507 do_read = 1;
508
509 do {
510 /* If we can write, or there is nothing to
511 * read, keep feeding the write pipe */
512 if ((stage1_written >= stage1_write_count)
513 || (1 == do_read)
514 || (1 != do_write))
515 break;
516
517 tmp_count = write(PARENT_WRITE_PIPE(pipe_fds),
518 &stage1_data[stage1_written],
519 strlen(&stage1_data[stage1_written]));
520 if ((-1 == tmp_count) && (EINTR != errno)) {
521 DBG_MSG("Error writing to PARENT_WRITE_PIPE!\n");
522 goto failed;
523 }
524 /* We were interrupted, try to write again */
525 if (-1 == tmp_count) {
526 errno = 0;
527 /* Make sure we retry */
528 tmp_count = 1;
529 continue;
530 }
531 /* What was written before, plus what
532 * we wrote now as well as the ending
533 * '\0' of the line */
534 stage1_written += tmp_count + 1;
535
536 /* Close the write pipe if we done
537 * writing to get a EOF signaled to
538 * bash */
539 if (stage1_written >= stage1_write_count) {
540 close(PARENT_WRITE_PIPE(pipe_fds));
541 PARENT_WRITE_PIPE(pipe_fds) = 0;
542 }
543 } while ((tmp_count > 0) && (stage1_written < stage1_write_count));
544
545 /* Reset tmp_count for below read loop */
546 tmp_count = 0;
547
548 do {
549 char *tmp_p;
550
551 if (1 != do_read)
552 continue;
553
554 tmp_count = read(PARENT_READ_PIPE(pipe_fds), buf,
555 PARSE_BUFFER_SIZE);
556 if ((-1 == tmp_count) && (EINTR != errno)) {
557 DBG_MSG("Error reading PARENT_READ_PIPE!\n");
558 goto failed;
559 }
560 /* We were interrupted, try to read again */
561 if ((-1 == tmp_count) || (0 == tmp_count)) {
562 errno = 0;
563 continue;
564 }
565
566 tmp_p = realloc(*data, write_count + tmp_count);
567 if (NULL == tmp_p) {
568 DBG_MSG("Failed to allocate buffer!\n");
569 goto failed;
570 }
571
572 memcpy(&tmp_p[write_count], buf, tmp_count);
573
574 *data = tmp_p;
575 write_count += tmp_count;
576 } while (tmp_count > 0);
577 } while (!(poll_fds[READ_PIPE].revents & POLLHUP));
578
579 failed:
580 /* Set old_errno to disable child exit code checking below */
581 if (0 != errno)
582 old_errno = errno;
583
584 free(stage1_data);
585
586 if (0 != PARENT_WRITE_PIPE(pipe_fds))
587 close(PARENT_WRITE_PIPE(pipe_fds));
588 close(PARENT_READ_PIPE(pipe_fds));
589
590 /* Restore the old signal handler for SIGPIPE */
591 sigaction(SIGPIPE, &act_old, NULL);
592
593 /* Wait for bash to finish */
594 waitpid(child_pid, &status, 0);
595 /* If old_errno is set, we had an error in the read loop, so do
596 * not worry about the child's exit code */
597 if (0 == old_errno) {
598 if ((!WIFEXITED(status)) || (0 != WEXITSTATUS(status))) {
599 DBG_MSG("Bash failed with status 0x%x!\n", status);
600 return -1;
601 }
602 } else {
603 /* Right, we had an error, so set errno, and exit */
604 errno = old_errno;
605 return -1;
606 }
607 }
608
609 return write_count;
610
611 /* Close parent side pipes */
612 error:
613 /* Close all pipes */
614 old_errno = errno;
615 if (0 != CHILD_READ_PIPE(pipe_fds))
616 close(CHILD_READ_PIPE(pipe_fds));
617 if (0 != CHILD_WRITE_PIPE(pipe_fds))
618 close(CHILD_WRITE_PIPE(pipe_fds));
619 if (0 != PARENT_READ_PIPE(pipe_fds))
620 close(PARENT_READ_PIPE(pipe_fds));
621 if (0 != PARENT_WRITE_PIPE(pipe_fds))
622 close(PARENT_WRITE_PIPE(pipe_fds));
623 /* close() might have changed it */
624 errno = old_errno;
625
626 return -1;
627 }
628
629 int write_legacy_stage3(FILE *output)
630 {
631 service_info_t *info;
632 char *service;
633 int count;
634 int index = 0;
635 int dep_count;
636 int i;
637
638 if (-1 == fileno(output)) {
639 DBG_MSG("Bad output stream!\n");
640 return -1;
641 }
642
643 fprintf(output, "rc_type_ineed=2\n");
644 fprintf(output, "rc_type_needsme=3\n");
645 fprintf(output, "rc_type_iuse=4\n");
646 fprintf(output, "rc_type_usesme=5\n");
647 fprintf(output, "rc_type_ibefore=6\n");
648 fprintf(output, "rc_type_iafter=7\n");
649 fprintf(output, "rc_type_broken=8\n");
650 fprintf(output, "rc_type_mtime=9\n");
651 fprintf(output, "rc_index_scale=10\n\n");
652 fprintf(output, "declare -a RC_DEPEND_TREE\n\n");
653
654 list_for_each_entry(info, &service_info_list, node) {
655 index++;
656 }
657 if (0 == index) {
658 EERROR("No services to generate dependency tree for!\n");
659 return -1;
660 }
661
662 fprintf(output, "RC_DEPEND_TREE[0]=%i\n\n", index);
663
664 index = 1;
665
666 list_for_each_entry(info, &service_info_list, node) {
667 fprintf(output, "RC_DEPEND_TREE[%i]=\"%s\"\n",
668 index * 10, info->name);
669
670 for (i = 0;i <= BROKEN;i++) {
671 dep_count = 0;
672
673 fprintf(output, "RC_DEPEND_TREE[%i+%i]=",
674 (index * 10), (i + 2));
675
676 STRING_LIST_FOR_EACH(info->depend_info[i], service, count) {
677 if (0 == dep_count)
678 fprintf(output, "\"%s", service);
679 else
680 fprintf(output, " %s", service);
681
682 dep_count++;
683 }
684
685 if (dep_count > 0)
686 fprintf(output, "\"\n");
687 else
688 fprintf(output, "\n");
689 }
690
691 fprintf(output, "RC_DEPEND_TREE[%i+9]=\"%li\"\n\n",
692 index * 10, info->mtime);
693 index++;
694 }
695
696 fprintf(output, "RC_GOT_DEPTREE_INFO=\"yes\"\n");
697
698 info = service_get_virtual("logger");
699 if (NULL == info) {
700 DBG_MSG("No service provides the 'logger' logger virtual!\n");
701 fprintf(output, "\nLOGGER_SERVICE=\n");
702 } else {
703 fprintf(output, "\nLOGGER_SERVICE=\"%s\"\n", info->name);
704 }
705
706
707 return 0;
708 }
709
710 int parse_cache(const char *data, size_t lenght)
711 {
712 service_info_t *info;
713 service_type_t type = ALL_SERVICE_TYPE_T;
714 rcscript_info_t *rs_info;
715 char *tmp_buf = NULL;
716 char *rc_name = NULL;
717 char *tmp_p;
718 char *token;
719 char *field;
720 int count;
721 int current = 0;
722 int retval;
723
724 if ((NULL == data) || (lenght <= 0)) {
725 DBG_MSG("Invalid argument passed!\n");
726 errno = EINVAL;
727 goto error;
728 }
729
730 while (current < lenght) {
731 count = buf_get_line((char *)data, lenght, current);
732
733 tmp_buf = strndup(&(data[current]), count);
734 if (NULL == tmp_buf) {
735 DBG_MSG("Failed to allocate temporary buffer!\n");
736 goto error;
737 }
738 tmp_p = tmp_buf;
739
740 /* Strip leading spaces/tabs */
741 while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t'))
742 tmp_p++;
743
744 /* Get FIELD name and FIELD value */
745 token = strsep(&tmp_p, " ");
746
747 /* FIELD name empty/bogus? */
748 if ((NULL == token)
749 || (0 == strlen(token))
750 /* We got an empty FIELD value */
751 || (NULL == tmp_p)
752 || (0 == strlen(tmp_p))) {
753 DBG_MSG("Parsing stopped due to short read!\n");
754 errno = EMSGSIZE;
755 goto error;
756 }
757
758 if (0 == strcmp(token, FIELD_RCSCRIPT)) {
759 DBG_MSG("Field = '%s', value = '%s'\n", token, tmp_p);
760
761 /* Add the service to the list, and initialize all data */
762 retval = service_add(tmp_p);
763 if (-1 == retval) {
764 DBG_MSG("Failed to add %s to service list!\n", tmp_p);
765 goto error;
766 }
767
768 info = service_get_info(tmp_p);
769 if (NULL == info) {
770 DBG_MSG("Failed to get info for '%s'!\n", tmp_p);
771 goto error;
772 }
773 /* Save the rc-script name for next passes of loop */
774 rc_name = info->name;
775
776 goto _continue;
777 }
778
779 if (NULL == rc_name) {
780 DBG_MSG("Other fields should come after '%s'!\n", FIELD_RCSCRIPT);
781 goto error;
782 }
783
784 if (0 == strcmp(token, FIELD_NEED))
785 type = NEED;
786 else if (0 == strcmp(token, FIELD_USE))
787 type = USE;
788 else if (0 == strcmp(token, FIELD_BEFORE))
789 type = BEFORE;
790 else if (0 == strcmp(token, FIELD_AFTER))
791 type = AFTER;
792 else if (0 == strcmp(token, FIELD_PROVIDE))
793 type = PROVIDE;
794 else if (0 == strcmp(token, FIELD_FAILED)) {
795 type = BROKEN;
796
797 /* FIXME: Need to think about what to do syntax BROKEN
798 * services */
799 EWARN("'%s' has syntax errors, please correct!\n", rc_name);
800 }
801
802 if (type < ALL_SERVICE_TYPE_T) {
803 /* Get the first value *
804 * As the values are passed to a bash function, and we
805 * then use 'echo $*' to parse them, they should only
806 * have one space between each value ... */
807 token = strsep(&tmp_p, " ");
808
809 /* Get the correct type name */
810 field = service_type_names[type];
811
812 while (NULL != token) {
813 DBG_MSG("Field = '%s', service = '%s', value = '%s'\n",
814 field, rc_name, token);
815
816 retval = service_add_dependency(rc_name, token, type);
817 if (-1 == retval) {
818 DBG_MSG("Failed to add dependency '%s' to service '%s', type '%s'!\n",
819 token, rc_name, field);
820 goto error;
821 }
822
823 /* Get the next value (if any) */
824 token = strsep(&tmp_p, " ");
825 }
826
827 goto _continue;
828 }
829
830 /* Fall through */
831 DBG_MSG("Unknown FIELD in data!\n");
832
833 _continue:
834 type = ALL_SERVICE_TYPE_T;
835 current += count + 1;
836 free(tmp_buf);
837 /* Do not free 'rc_name', as it should be consistant
838 * across loops */
839 }
840
841 /* Set the mtimes
842 * FIXME: Can drop this when we no longer need write_legacy_stage3() */
843 list_for_each_entry(rs_info, &rcscript_list, node) {
844 rc_name = gbasename(rs_info->filename);
845 if (NULL == service_get_info(rc_name))
846 continue;
847
848 retval = service_set_mtime(rc_name, rs_info->mtime);
849 if (-1 == retval) {
850 DBG_MSG("Failed to set mtime for service '%s'!\n", rc_name);
851 return -1;
852 }
853 }
854
855 return 0;
856
857 error:
858 free(tmp_buf);
859
860 return -1;
861 }
862
863 size_t parse_print_start(char **data, size_t index)
864 {
865 size_t write_count = index;
866
867 PRINT_TO_BUFFER(data, write_count, error,
868 ". /sbin/functions.sh\n"
869 "[ -e /etc/rc.conf ] && . /etc/rc.conf\n"
870 "\n"
871 /* "set -e\n" */
872 "\n");
873
874 return write_count;
875
876 error:
877 return -1;
878 }
879
880 size_t parse_print_header(char *scriptname, char **data, size_t index)
881 {
882 size_t write_count = index;
883
884 PRINT_TO_BUFFER(data, write_count, error,
885 "#*** %s ***\n"
886 "\n"
887 "myservice=\"%s\"\n"
888 "echo \"RCSCRIPT ${myservice}\"\n"
889 "\n",
890 scriptname, scriptname);
891
892 return write_count;
893
894 error:
895 return -1;
896 }
897
898 size_t parse_print_body(char *scriptname, char **data, size_t index)
899 {
900 size_t write_count = index;
901 char *tmp_buf = NULL;
902 char *tmp_ptr;
903 char *base;
904 char *ext;
905
906 tmp_buf = strndup(scriptname, strlen(scriptname));
907 if (NULL == tmp_buf) {
908 DBG_MSG("Failed to allocate temporary buffer!\n");
909 goto error;
910 }
911
912 /*
913 * Rather do the next block in C than bash, in case we want to
914 * use ash or another shell in the place of bash
915 */
916
917 /* bash: base="${myservice%%.*}" */
918 base = tmp_buf;
919 tmp_ptr = strchr(tmp_buf, '.');
920 if (NULL != tmp_ptr) {
921 tmp_ptr[0] = '\0';
922 tmp_ptr++;
923 } else {
924 tmp_ptr = tmp_buf;
925 }
926 /* bash: ext="${myservice##*.}" */
927 ext = strrchr(tmp_ptr, '.');
928 if (NULL == ext)
929 ext = tmp_ptr;
930
931 PRINT_TO_BUFFER(data, write_count, error,
932 "\n"
933 "(\n"
934 " # Get settings for rc-script ...\n"
935 " [ -e \"/etc/conf.d/${myservice}\" ] && \\\n"
936 " . \"/etc/conf.d/${myservice}\"\n"
937 " [ -e /etc/conf.d/net ] && \\\n"
938 " [ \"%s\" = \"net\" ] && \\\n"
939 " [ \"%s\" != \"${myservice}\" ] && \\\n"
940 " . /etc/conf.d/net\n"
941 " depend() {\n"
942 " return 0\n"
943 " }\n"
944 " \n"
945 " # Actual depend() function ...\n"
946 " (\n"
947 " set -e\n"
948 " . \"/etc/init.d/%s\" >/dev/null 2>&1\n"
949 " set +e\n"
950 " \n"
951 " need() {\n"
952 " [ \"$#\" -gt 0 ] && echo \"NEED $*\"; return 0\n"
953 " }\n"
954 " \n"
955 " use() {\n"
956 " [ \"$#\" -gt 0 ] && echo \"USE $*\"; return 0\n"
957 " }\n"
958 " \n"
959 " before() {\n"
960 " [ \"$#\" -gt 0 ] && echo \"BEFORE $*\"; return 0\n"
961 " }\n"
962 " \n"
963 " after() {\n"
964 " [ \"$#\" -gt 0 ] && echo \"AFTER $*\"; return 0\n"
965 " }\n"
966 " \n"
967 " provide() {\n"
968 " [ \"$#\" -gt 0 ] && echo \"PROVIDE $*\"; return 0\n"
969 " }\n"
970 " \n"
971 " depend\n"
972 " ) || echo \"FAILED ${myservice}\"\n"
973 ")\n"
974 "\n\n",
975 base, ext, scriptname);
976
977 return write_count;
978
979 error:
980 return -1;
981 }
982

  ViewVC Help
Powered by ViewVC 1.1.20