Contents of /trunk/mkinitrd-magellan/busybox/networking/udhcp/script.c
Parent Directory | Revision Log
Revision 984 -
(show annotations)
(download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 7003 byte(s)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 7003 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 | /* vi: set sw=4 ts=4: */ |
2 | /* script.c |
3 | * |
4 | * Functions to call the DHCP client notification scripts |
5 | * |
6 | * Russ Dill <Russ.Dill@asu.edu> July 2001 |
7 | * |
8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
9 | */ |
10 | |
11 | #include "common.h" |
12 | #include "dhcpc.h" |
13 | #include "options.h" |
14 | |
15 | |
16 | /* get a rough idea of how long an option will be (rounding up...) */ |
17 | static const uint8_t len_of_option_as_string[] = { |
18 | [OPTION_IP] = sizeof("255.255.255.255 "), |
19 | [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2, |
20 | [OPTION_STATIC_ROUTES]= sizeof("255.255.255.255/32 255.255.255.255 "), |
21 | [OPTION_STRING] = 1, |
22 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
23 | [OPTION_STR1035] = 1, |
24 | #endif |
25 | [OPTION_BOOLEAN] = sizeof("yes "), |
26 | [OPTION_U8] = sizeof("255 "), |
27 | [OPTION_U16] = sizeof("65535 "), |
28 | [OPTION_S16] = sizeof("-32768 "), |
29 | [OPTION_U32] = sizeof("4294967295 "), |
30 | [OPTION_S32] = sizeof("-2147483684 "), |
31 | }; |
32 | |
33 | |
34 | /* note: ip is a pointer to an IP in network order, possibly misaliged */ |
35 | static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) |
36 | { |
37 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); |
38 | } |
39 | |
40 | |
41 | /* really simple implementation, just count the bits */ |
42 | static int mton(uint32_t mask) |
43 | { |
44 | int i = 0; |
45 | mask = ntohl(mask); /* 111110000-like bit pattern */ |
46 | while (mask) { |
47 | i++; |
48 | mask <<= 1; |
49 | } |
50 | return i; |
51 | } |
52 | |
53 | |
54 | /* Create "opt_name=opt_value" string */ |
55 | static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name) |
56 | { |
57 | unsigned upper_length; |
58 | int len, type, optlen; |
59 | uint16_t val_u16; |
60 | int16_t val_s16; |
61 | uint32_t val_u32; |
62 | int32_t val_s32; |
63 | char *dest, *ret; |
64 | |
65 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ |
66 | len = option[OPT_LEN - OPT_DATA]; |
67 | type = type_p->flags & TYPE_MASK; |
68 | optlen = dhcp_option_lengths[type]; |
69 | upper_length = len_of_option_as_string[type] * (len / optlen); |
70 | |
71 | dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); |
72 | dest += sprintf(ret, "%s=", opt_name); |
73 | |
74 | while (len >= optlen) { |
75 | switch (type) { |
76 | case OPTION_IP_PAIR: |
77 | dest += sprint_nip(dest, "", option); |
78 | *dest++ = '/'; |
79 | option += 4; |
80 | optlen = 4; |
81 | case OPTION_IP: /* Works regardless of host byte order. */ |
82 | dest += sprint_nip(dest, "", option); |
83 | break; |
84 | case OPTION_BOOLEAN: |
85 | dest += sprintf(dest, *option ? "yes" : "no"); |
86 | break; |
87 | case OPTION_U8: |
88 | dest += sprintf(dest, "%u", *option); |
89 | break; |
90 | case OPTION_U16: |
91 | move_from_unaligned16(val_u16, option); |
92 | dest += sprintf(dest, "%u", ntohs(val_u16)); |
93 | break; |
94 | case OPTION_S16: |
95 | move_from_unaligned16(val_s16, option); |
96 | dest += sprintf(dest, "%d", ntohs(val_s16)); |
97 | break; |
98 | case OPTION_U32: |
99 | move_from_unaligned32(val_u32, option); |
100 | dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32)); |
101 | break; |
102 | case OPTION_S32: |
103 | move_from_unaligned32(val_s32, option); |
104 | dest += sprintf(dest, "%ld", (long) ntohl(val_s32)); |
105 | break; |
106 | case OPTION_STRING: |
107 | memcpy(dest, option, len); |
108 | dest[len] = '\0'; |
109 | return ret; /* Short circuit this case */ |
110 | case OPTION_STATIC_ROUTES: { |
111 | /* Option binary format: |
112 | * mask [one byte, 0..32] |
113 | * ip [big endian, 0..4 bytes depending on mask] |
114 | * router [big endian, 4 bytes] |
115 | * may be repeated |
116 | * |
117 | * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2" |
118 | */ |
119 | const char *pfx = ""; |
120 | |
121 | while (len >= 1 + 4) { /* mask + 0-byte ip + router */ |
122 | uint32_t nip; |
123 | uint8_t *p; |
124 | unsigned mask; |
125 | int bytes; |
126 | |
127 | mask = *option++; |
128 | if (mask > 32) |
129 | break; |
130 | len--; |
131 | |
132 | nip = 0; |
133 | p = (void*) &nip; |
134 | bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */ |
135 | while (--bytes >= 0) { |
136 | *p++ = *option++; |
137 | len--; |
138 | } |
139 | if (len < 4) |
140 | break; |
141 | |
142 | /* print ip/mask */ |
143 | dest += sprint_nip(dest, pfx, (void*) &nip); |
144 | pfx = " "; |
145 | dest += sprintf(dest, "/%u ", mask); |
146 | /* print router */ |
147 | dest += sprint_nip(dest, "", option); |
148 | option += 4; |
149 | len -= 4; |
150 | } |
151 | |
152 | return ret; |
153 | } |
154 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
155 | case OPTION_STR1035: |
156 | /* unpack option into dest; use ret for prefix (i.e., "optname=") */ |
157 | dest = dname_dec(option, len, ret); |
158 | if (dest) { |
159 | free(ret); |
160 | return dest; |
161 | } |
162 | /* error. return "optname=" string */ |
163 | return ret; |
164 | #endif |
165 | } |
166 | option += optlen; |
167 | len -= optlen; |
168 | if (len <= 0) |
169 | break; |
170 | *dest++ = ' '; |
171 | *dest = '\0'; |
172 | } |
173 | return ret; |
174 | } |
175 | |
176 | |
177 | /* put all the parameters into an environment */ |
178 | static char **fill_envp(struct dhcp_packet *packet) |
179 | { |
180 | int num_options = 0; |
181 | int i; |
182 | char **envp, **curr; |
183 | const char *opt_name; |
184 | uint8_t *temp; |
185 | uint8_t over = 0; |
186 | |
187 | if (packet) { |
188 | for (i = 0; dhcp_options[i].code; i++) { |
189 | if (get_option(packet, dhcp_options[i].code)) { |
190 | num_options++; |
191 | if (dhcp_options[i].code == DHCP_SUBNET) |
192 | num_options++; /* for mton */ |
193 | } |
194 | } |
195 | if (packet->siaddr_nip) |
196 | num_options++; |
197 | temp = get_option(packet, DHCP_OPTION_OVERLOAD); |
198 | if (temp) |
199 | over = *temp; |
200 | if (!(over & FILE_FIELD) && packet->file[0]) |
201 | num_options++; |
202 | if (!(over & SNAME_FIELD) && packet->sname[0]) |
203 | num_options++; |
204 | } |
205 | |
206 | curr = envp = xzalloc(sizeof(char *) * (num_options + 3)); |
207 | *curr = xasprintf("interface=%s", client_config.interface); |
208 | putenv(*curr++); |
209 | |
210 | if (packet == NULL) |
211 | return envp; |
212 | |
213 | *curr = xmalloc(sizeof("ip=255.255.255.255")); |
214 | sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); |
215 | putenv(*curr++); |
216 | |
217 | opt_name = dhcp_option_strings; |
218 | i = 0; |
219 | while (*opt_name) { |
220 | temp = get_option(packet, dhcp_options[i].code); |
221 | if (!temp) |
222 | goto next; |
223 | *curr = xmalloc_optname_optval(temp, &dhcp_options[i], opt_name); |
224 | putenv(*curr++); |
225 | |
226 | /* Fill in a subnet bits option for things like /24 */ |
227 | if (dhcp_options[i].code == DHCP_SUBNET) { |
228 | uint32_t subnet; |
229 | move_from_unaligned32(subnet, temp); |
230 | *curr = xasprintf("mask=%d", mton(subnet)); |
231 | putenv(*curr++); |
232 | } |
233 | next: |
234 | opt_name += strlen(opt_name) + 1; |
235 | i++; |
236 | } |
237 | if (packet->siaddr_nip) { |
238 | *curr = xmalloc(sizeof("siaddr=255.255.255.255")); |
239 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); |
240 | putenv(*curr++); |
241 | } |
242 | if (!(over & FILE_FIELD) && packet->file[0]) { |
243 | /* watch out for invalid packets */ |
244 | packet->file[sizeof(packet->file) - 1] = '\0'; |
245 | *curr = xasprintf("boot_file=%s", packet->file); |
246 | putenv(*curr++); |
247 | } |
248 | if (!(over & SNAME_FIELD) && packet->sname[0]) { |
249 | /* watch out for invalid packets */ |
250 | packet->sname[sizeof(packet->sname) - 1] = '\0'; |
251 | *curr = xasprintf("sname=%s", packet->sname); |
252 | putenv(*curr++); |
253 | } |
254 | return envp; |
255 | } |
256 | |
257 | |
258 | /* Call a script with a par file and env vars */ |
259 | void FAST_FUNC udhcp_run_script(struct dhcp_packet *packet, const char *name) |
260 | { |
261 | char **envp, **curr; |
262 | char *argv[3]; |
263 | |
264 | if (client_config.script == NULL) |
265 | return; |
266 | |
267 | envp = fill_envp(packet); |
268 | |
269 | /* call script */ |
270 | log1("Executing %s %s", client_config.script, name); |
271 | argv[0] = (char*) client_config.script; |
272 | argv[1] = (char*) name; |
273 | argv[2] = NULL; |
274 | wait4pid(spawn(argv)); |
275 | |
276 | for (curr = envp; *curr; curr++) { |
277 | log2(" %s", *curr); |
278 | bb_unsetenv(*curr); |
279 | free(*curr); |
280 | } |
281 | free(envp); |
282 | } |