util-linux: move package to package/system/utils
[openwrt.git] / package / hotplug2 / patches / 140-worker_fork_fix.patch
1 --- a/action.c
2 +++ b/action.c
3 @@ -39,7 +39,7 @@ static void action_dumb(const struct set
4   * Returns: Newly allocated string in "key=value" form
5   *
6   */
7 -static char* alloc_env(const char *key, const char *value) {
8 +char* alloc_env(const char *key, const char *value) {
9         size_t keylen, vallen;
10         char *combined;
11  
12 --- a/action.h
13 +++ b/action.h
14 @@ -12,5 +12,6 @@
15  #include "settings.h"
16  
17  void action_perform(struct settings_t *, struct uevent_t *);
18 +char* alloc_env(const char *, const char *);
19  #endif /* ifndef ACTION_H */
20  
21 --- a/workers/worker_fork.c
22 +++ b/workers/worker_fork.c
23 @@ -1,6 +1,69 @@
24  #include "worker_fork.h"
25  
26  static struct worker_fork_ctx_t *global_ctx;
27 +static struct worker_fork_uevent_t *uevent_list;
28 +
29 +static void worker_fork_uevent_free(struct worker_fork_uevent_t *node) {
30 +       uevent_free(node->uevent);
31 +       free(node);
32 +}
33 +
34 +static void worker_fork_uevent_add(void *in_ctx, struct uevent_t *uevent) {
35 +       char **env;
36 +       int i;
37 +       struct worker_fork_ctx_t *ctx = in_ctx;
38 +       struct worker_fork_uevent_t *node, *walker;
39 +
40 +       node = malloc(sizeof (struct worker_fork_uevent_t));
41 +       node->uevent = uevent_dup(uevent);
42 +       node->next = NULL;
43 +
44 +       if (!uevent_list) uevent_list = node;
45 +       else {
46 +               /*
47 +                * Put events that need to fork first and in reverse order
48 +                */
49 +               env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
50 +               for (i = 0; i < node->uevent->env_vars_c; i++) {
51 +                       env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
52 +                       putenv(env[i]);
53 +               }
54 +               if (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW) {
55 +                       node->next = uevent_list;
56 +                       uevent_list = node;
57 +               }
58 +               else {
59 +                       for (walker = uevent_list; walker->next; walker = walker->next);
60 +                       walker->next = node;
61 +               }
62 +               for (i = 0; i < node->uevent->env_vars_c; i++) {
63 +                       unsetenv(node->uevent->env_vars[i].key);
64 +                       free(env[i]);
65 +               }
66 +               free(env);
67 +       }
68 +}
69 +
70 +static void worker_fork_uevent_del(struct worker_fork_uevent_t *node) {
71 +       struct worker_fork_uevent_t *walker;
72 +
73 +       if (node == uevent_list) {
74 +               uevent_list = node->next;
75 +       }
76 +       else {
77 +               for (walker = uevent_list; walker->next; walker = walker->next)
78 +                       if (walker->next == node) walker->next = node->next;
79 +       }
80 +       worker_fork_uevent_free(node);
81 +}
82 +
83 +static void worker_fork_uevent_empty(void) {
84 +       struct worker_fork_uevent_t *walker;
85 +
86 +       if (!uevent_list) return;
87 +       for (walker = uevent_list; walker->next; walker = walker->next) worker_fork_uevent_free(walker);
88 +       uevent_list = NULL;
89 +}
90  
91  /**
92   * Destroys data structures related to the given child ID (not PID).
93 @@ -315,6 +378,8 @@ static void *worker_fork_init(struct set
94         struct worker_fork_ctx_t *ctx;
95         PRINTFUNC();
96  
97 +       uevent_list = NULL;
98 +
99         ctx = malloc(sizeof(struct worker_fork_ctx_t));
100         ctx->children = NULL;
101         ctx->children_count = 0;
102 @@ -376,26 +441,39 @@ static void worker_fork_deinit(void *in_
103         free(ctx->children);
104         free(ctx);
105         global_ctx = NULL;
106 +       worker_fork_uevent_empty();
107  }
108  
109  
110  static int worker_fork_process(void *in_ctx, struct uevent_t *uevent) {
111 +       char **env;
112         int i;
113         struct worker_fork_child_t *child;
114         struct worker_fork_ctx_t *ctx = in_ctx;
115 +       struct worker_fork_uevent_t *node, *walker;
116 +       event_seqnum_t seqnum;
117 +
118 +       worker_fork_uevent_add(ctx, uevent);
119 +       walker = uevent_list;
120  
121         /*
122 -        * A big loop, because if we fail to process the event,
123 +        * A big loop, because if we fail to process the events,
124          * we don't want to give up.
125          *
126          * TODO: Decide if we want to limit the number of attempts
127          * or set a time limit before reporting terminal failure.
128          */
129         do {
130 +               /*
131 +                * If more events are waiting, return to receive them
132 +                */
133 +               if (!seqnum_get(&seqnum) && seqnum > uevent->seqnum) break;
134 +
135 +               node = walker;
136                 worker_fork_update_children(ctx);
137  
138                 child = NULL;
139 -               for (i = 0; i < ctx->children_count; i++) {
140 +               for (i = 0; i < ctx->children_count && i < ctx->max_children; i++) {
141                         if (ctx->children[i]->busy == 0) {
142                                 child = ctx->children[i];
143                                 break;
144 @@ -406,21 +484,40 @@ static int worker_fork_process(void *in_
145                  * No child process is currently available.
146                  */
147                 if (child == NULL) {
148 +                       bool is_slow;
149 +
150 +                       env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
151 +                       for (i = 0; i < node->uevent->env_vars_c; i++) {
152 +                               env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
153 +                               putenv(env[i]);
154 +                       }
155 +
156 +                       is_slow = !!(ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_MASK_SLOW);
157 +
158 +                       for (i = 0; i < node->uevent->env_vars_c; i++) {
159 +                               unsetenv(node->uevent->env_vars[i].key);
160 +                               free(env[i]);
161 +                       }
162 +                       free(env);
163 +
164                         /*
165                          * Are the matching rules trivial enough that we
166                          * can execute them in the main process?
167                          */
168 -                       if (ctx->always_fork == 0 && ctx->settings->dumb == 0 && 
169 -                       (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_MASK_SLOW) == 0) {
170 -                               action_perform(ctx->settings, uevent);
171 +                       if (ctx->always_fork == 0 && ctx->settings->dumb == 0 && !is_slow) {
172 +                               action_perform(ctx->settings, node->uevent);
173 +                               walker = walker->next;
174 +                               worker_fork_uevent_del(node);
175 +                               if (walker) continue;
176                                 break;
177                         }
178 -                       
179 +
180                         /*
181                          * We have to fork off a new child.
182                          */
183                         if (ctx->children_count < ctx->max_children)
184                                 child = worker_fork_spawn(ctx);
185 +
186                 }
187  
188                 /*
189 @@ -428,9 +525,14 @@ static int worker_fork_process(void *in_
190                  */
191                 if (child != NULL) {
192                         child->busy = 1;
193 -                       if (!worker_fork_relay_event(child->event_fd, uevent));
194 -                               break;
195 -                       child->busy = 0;
196 +                       if (worker_fork_relay_event(child->event_fd, node->uevent)) {
197 +                               child->busy = 0;
198 +                               continue;
199 +                       }
200 +                       walker = walker->next;
201 +                       worker_fork_uevent_del(node);
202 +                       if (walker) continue;
203 +                       break;
204                 }
205  
206                 /* 
207 --- a/uevent.c
208 +++ b/uevent.c
209 @@ -132,6 +132,8 @@ struct uevent_t *uevent_dup(const struct
210         
211         dest = xmalloc(sizeof(struct uevent_t));
212         dest->action = src->action;
213 +       dest->seqnum = src->seqnum;
214 +       dest->action_str = strdup(src->action_str);
215         dest->env_vars_c = src->env_vars_c;
216         dest->env_vars = xmalloc(sizeof(struct env_var_t) * dest->env_vars_c);
217         dest->plain_s = src->plain_s;
218 --- a/workers/worker_fork.h
219 +++ b/workers/worker_fork.h
220 @@ -5,6 +5,7 @@
221  #include <sys/types.h>
222  #include <sys/select.h>
223  #include <unistd.h>
224 +#include <stdbool.h>
225  
226  #include "../rules/execution.h"
227  
228 @@ -35,4 +36,9 @@ struct worker_fork_ctx_t {
229         struct settings_t                       *settings;
230  };
231  
232 +struct worker_fork_uevent_t {
233 +       struct uevent_t *uevent;
234 +       struct worker_fork_uevent_t *next;
235 +};
236 +
237  #endif