6419fe9167dc978f34479636cba5f6c3b35f7c65
[project/netifd.git] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <getopt.h>
5 #include <unistd.h>
6
7 #include "netifd.h"
8 #include "ubus.h"
9 #include "config.h"
10 #include "system.h"
11 #include "interface.h"
12
13 unsigned int debug_mask = 0;
14 const char *main_path = DEFAULT_MAIN_PATH;
15 const char *resolv_conf = DEFAULT_RESOLV_CONF;
16 static char **global_argv;
17
18 static struct list_head process_list = LIST_HEAD_INIT(process_list);
19 static struct list_head fds = LIST_HEAD_INIT(fds);
20
21 static void
22 netifd_process_cb(struct uloop_process *proc, int ret)
23 {
24         struct netifd_process *np;
25         np = container_of(proc, struct netifd_process, uloop);
26         list_del(&np->list);
27         return np->cb(np, ret);
28 }
29
30 int
31 netifd_start_process(const char **argv, char **env, struct netifd_process *proc)
32 {
33         struct netifd_fd *fd;
34         int pid;
35
36         netifd_kill_process(proc);
37
38         if ((pid = fork()) < 0)
39                 return -1;
40
41         if (!pid) {
42                 if (env) {
43                         while (*env) {
44                                 putenv(*env);
45                                 env++;
46                         }
47                 }
48                 if (proc->dir_fd >= 0)
49                         fchdir(proc->dir_fd);
50
51                 /* close all non-essential fds */
52                 list_for_each_entry(fd, &fds, list) {
53                         if (fd->proc == proc)
54                                 continue;
55                         close(fd->fd);
56                 }
57
58                 execvp(argv[0], (char **) argv);
59                 exit(127);
60         }
61
62         if (pid < 0)
63                 return -1;
64
65         proc->uloop.cb = netifd_process_cb;
66         proc->uloop.pid = pid;
67         uloop_process_add(&proc->uloop);
68         list_add_tail(&proc->list, &process_list);
69
70         return 0;
71 }
72
73 void
74 netifd_kill_process(struct netifd_process *proc)
75 {
76         if (!proc->uloop.pending)
77                 return;
78
79         kill(proc->uloop.pid, SIGTERM);
80         uloop_process_delete(&proc->uloop);
81         list_del(&proc->list);
82 }
83
84 void
85 netifd_fd_add(struct netifd_fd *fd)
86 {
87         list_add_tail(&fd->list, &fds);
88 }
89
90 void
91 netifd_fd_delete(struct netifd_fd *fd)
92 {
93         list_del(&fd->list);
94 }
95
96 static void netifd_do_restart(struct uloop_timeout *timeout)
97 {
98         execvp(global_argv[0], global_argv);
99 }
100
101 static void netifd_do_reload(struct uloop_timeout *timeout)
102 {
103         config_init_interfaces(NULL);
104 }
105
106 static struct uloop_timeout main_timer;
107
108 void netifd_reload(void)
109 {
110         main_timer.cb = netifd_do_reload;
111         uloop_timeout_set(&main_timer, 100);
112 }
113
114 void netifd_restart(void)
115 {
116         main_timer.cb = netifd_do_restart;
117         interface_set_down(NULL);
118         uloop_timeout_set(&main_timer, 1000);
119 }
120
121 static int usage(const char *progname)
122 {
123         fprintf(stderr, "Usage: %s [options]\n"
124                 "Options:\n"
125                 " -d <mask>:            Mask for debug messages\n"
126                 " -s <path>:            Path to the ubus socket\n"
127                 " -p <path>:            Path to netifd addons (default: %s)\n"
128                 " -h <path>:            Path to the hotplug script\n"
129                 " -r <path>:            Path to resolv.conf\n"
130                 "                       (default: "DEFAULT_HOTPLUG_PATH")\n"
131                 "\n", progname, main_path);
132
133         return 1;
134 }
135
136 static void
137 netifd_handle_signal(int signo)
138 {
139         uloop_end();
140 }
141
142 static void
143 netifd_setup_signals(void)
144 {
145         struct sigaction s;
146
147         memset(&s, 0, sizeof(s));
148         s.sa_handler = netifd_handle_signal;
149         s.sa_flags = 0;
150         sigaction(SIGINT, &s, NULL);
151         sigaction(SIGTERM, &s, NULL);
152         sigaction(SIGUSR1, &s, NULL);
153         sigaction(SIGUSR2, &s, NULL);
154 }
155
156 static void
157 netifd_kill_processes(void)
158 {
159         struct netifd_process *proc, *tmp;
160
161         list_for_each_entry_safe(proc, tmp, &process_list, list)
162                 netifd_kill_process(proc);
163 }
164
165 int main(int argc, char **argv)
166 {
167         const char *socket = NULL;
168         int ch;
169
170         global_argv = argv;
171
172         while ((ch = getopt(argc, argv, "d:s:p:h:r:")) != -1) {
173                 switch(ch) {
174                 case 'd':
175                         debug_mask = strtoul(optarg, NULL, 0);
176                         break;
177                 case 's':
178                         socket = optarg;
179                         break;
180                 case 'p':
181                         main_path = optarg;
182                         break;
183                 case 'h':
184                         hotplug_cmd_path = optarg;
185                         break;
186                 case 'r':
187                         resolv_conf = optarg;
188                         break;
189                 default:
190                         return usage(argv[0]);
191                 }
192         }
193
194         netifd_setup_signals();
195         if (netifd_ubus_init(socket) < 0) {
196                 fprintf(stderr, "Failed to connect to ubus\n");
197                 return 1;
198         }
199
200         if (system_init()) {
201                 fprintf(stderr, "Failed to initialize system control\n");
202                 return 1;
203         }
204
205         config_init_interfaces(NULL);
206
207         uloop_run();
208         netifd_kill_processes();
209
210         netifd_ubus_done();
211
212         return 0;
213 }