kmodloader: use avl tree and calloc_a
[project/ubox.git] / lsbloader.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; version 2 of the License
5  *
6  *   This program is distributed in the hope that it will be useful,
7  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
8  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  *   GNU General Public License for more details.
10  *
11  *   You should have received a copy of the GNU General Public License
12  *   along with this program; if not, write to the Free Software
13  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
14  *
15  *   Copyright (C) 2012 John Crispin <blogic@openwrt.org> 
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #define __USE_GNU
21 #include <string.h>
22 #include <regex.h>
23 #include <glob.h>
24
25 #include <libubox/list.h>
26 #include <libubox/blobmsg_json.h>
27 #include "libubus.h"
28
29 struct initd {
30         struct list_head list;
31
32         char *name;
33         char *exec;
34         char *desc;
35         char *tpl;
36         char **deps;
37         int start;
38         int stop;
39 };
40
41 static LIST_HEAD(initds);
42 static regex_t pat_provides, pat_require, pat_start, pat_stop, pat_desc, pat_exec, pat_tpl;
43 static struct ubus_context *ctx;
44 static struct blob_buf b;
45 static uint32_t service;
46
47 static void initd_free(struct initd *i)
48 {
49         if (i->name)
50                 free(i->name);
51         if (i->exec)
52                 free(i->exec);
53         if (i->desc)
54                 free(i->desc);
55         if (i->tpl)
56                 free(i->tpl);
57 }
58
59 static int initd_parse(const char *file)
60 {
61         FILE *fp;
62         struct initd *i;
63         regmatch_t matches[2];
64         char buffer[1024];
65         ssize_t len;
66
67         fp = fopen(file, "r");
68         if (!fp) {
69                 fprintf(stderr, "failed to open %s\n", file);
70                 return -1;
71         }
72         len = fread(buffer, 1, sizeof(buffer) - 1, fp);
73         fclose(fp);
74
75         if (len < 1) {
76                 fprintf(stderr, "failed to read from %s\n", file);
77                 return -1;
78         }
79         buffer[len] = '\0';
80
81         i = malloc(sizeof(struct initd));
82         if (!i) {
83                 fprintf(stderr, "failed to alloc initd struct\n");
84                 return -1;
85         }
86         memset(i, 0, sizeof(*i));
87
88         if (!regexec(&pat_provides, buffer, 2, matches, 0))
89                 i->name = strndup(buffer + matches[1].rm_so, (size_t)matches[1].rm_eo - matches[1].rm_so);
90         if (!regexec(&pat_exec, buffer, 2, matches, 0))
91                 i->exec = strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
92         if (!regexec(&pat_desc, buffer, 2, matches, 0))
93                 i->desc = strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
94         if (!regexec(&pat_tpl, buffer, 2, matches, 0))
95                 i->tpl = strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
96         if (!regexec(&pat_start, buffer, 2, matches, 0))
97                 i->start += atoi(buffer + matches[1].rm_so);
98         if (!regexec(&pat_stop, buffer, 2, matches, 0))
99                 i->stop += atoi(buffer + matches[1].rm_so);
100
101         if (i->name && i->exec)
102                 list_add(&i->list, &initds);
103         else
104                 initd_free(i);
105
106         return 0;
107 }
108
109 static void initd_init(void)
110 {
111         int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
112         glob_t gl;
113
114         regcomp(&pat_provides, "# Provides:[ \t]*([a-zA-Z0-9]+)", REG_EXTENDED);
115         regcomp(&pat_require, "# Required-Start:[ \t]*([a-zA-Z0-9 ]+)", REG_EXTENDED);
116         regcomp(&pat_start, "# Default-Start:[ \t]*([0-9])", REG_EXTENDED);
117         regcomp(&pat_stop, "# Default-Stop:[ \t]*([0-9])", REG_EXTENDED);
118         regcomp(&pat_desc, "# Description:[ \t]*([a-zA-Z0-9 ]+)", REG_EXTENDED);
119         regcomp(&pat_exec, "# X-Exec:[ \t]*([a-zA-Z0-9/ ]+)", REG_EXTENDED);
120         regcomp(&pat_tpl, "# X-Template:[ \t]*([a-zA-Z0-9/.]+)", REG_EXTENDED);
121
122         if (glob("/etc/rc.d/P*", gl_flags, NULL, &gl) >= 0) {
123                 int j;
124                 for (j = 0; j < gl.gl_pathc; j++)
125                         initd_parse(gl.gl_pathv[j]);
126         }
127         globfree(&gl);
128
129         regfree(&pat_provides);
130         regfree(&pat_require);
131         regfree(&pat_start);
132         regfree(&pat_stop);
133         regfree(&pat_desc);
134         regfree(&pat_exec);
135         regfree(&pat_tpl);
136 }
137
138 static int init_services(void)
139 {
140         struct initd *i;
141         void *instances, *instance, *command;
142
143         list_for_each_entry(i, &initds, list) {
144                 char *t;
145
146                 blob_buf_init(&b, 0);
147                 blobmsg_add_string(&b, "name", i->name);
148                 instances = blobmsg_open_table(&b, "instances");
149                 instance = blobmsg_open_table(&b, "instance");
150                 command = blobmsg_open_array(&b, "command");
151                 t = strtok(i->exec, " ");
152                 while (t) {
153                         blobmsg_add_string(&b, NULL, t);
154                         t = strtok(NULL, " ");
155                 }
156                 blobmsg_close_array(&b, command);
157                 blobmsg_close_table(&b, instance);
158                 blobmsg_close_table(&b, instances);
159                 ubus_invoke(ctx, service, "add", b.head, NULL, 0, 1000);
160         }
161
162         return 0;
163 }
164
165 int main(int argc, char **argv)
166 {
167         int ret;
168
169         initd_init();
170
171         if (list_empty(&initds))
172                 return 0;
173
174         ctx = ubus_connect(NULL);
175         if (!ctx) {
176                 fprintf(stderr, "Failed to connect to ubus\n");
177                 return -1;
178         }
179
180         ret = ubus_lookup_id(ctx, "service", &service);
181         if (ret) {
182                 fprintf(stderr, "Failed to find service object: %s\n", ubus_strerror(ret));
183                 return -1;
184         }
185
186         return init_services();
187 }