Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/networking/udhcp/script.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 14  Line 14 
14    
15    
16  /* get a rough idea of how long an option will be (rounding up...) */  /* get a rough idea of how long an option will be (rounding up...) */
17  static const uint8_t max_option_length[] = {  static const uint8_t len_of_option_as_string[] = {
18   [OPTION_IP] = sizeof("255.255.255.255 "),   [OPTION_IP] = sizeof("255.255.255.255 "),
19   [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,   [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,   [OPTION_STRING] = 1,
22  #if ENABLE_FEATURE_UDHCP_RFC3397  #if ENABLE_FEATURE_UDHCP_RFC3397
23   [OPTION_STR1035] = 1,   [OPTION_STR1035] = 1,
# Line 30  static const uint8_t max_option_length[] Line 31  static const uint8_t max_option_length[]
31  };  };
32    
33    
34  static inline int upper_length(int length, int opt_index)  /* 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 max_option_length[opt_index] *   return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
  (length / dhcp_option_lengths[opt_index]);  
 }  
   
   
 static int sprintip(char *dest, const char *pre, const uint8_t *ip)  
 {  
  return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);  
38  }  }
39    
40    
# Line 56  static int mton(uint32_t mask) Line 51  static int mton(uint32_t mask)
51  }  }
52    
53    
54  /* Allocate and fill with the text of option 'option'. */  /* Create "opt_name=opt_value" string */
55  static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)  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;   int len, type, optlen;
59   uint16_t val_u16;   uint16_t val_u16;
60   int16_t val_s16;   int16_t val_s16;
# Line 66  static char *alloc_fill_opts(uint8_t *op Line 62  static char *alloc_fill_opts(uint8_t *op
62   int32_t val_s32;   int32_t val_s32;
63   char *dest, *ret;   char *dest, *ret;
64    
65   len = option[OPT_LEN - 2];   /* 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;   type = type_p->flags & TYPE_MASK;
68   optlen = dhcp_option_lengths[type];   optlen = dhcp_option_lengths[type];
69     upper_length = len_of_option_as_string[type] * (len / optlen);
70    
71   dest = ret = xmalloc(upper_length(len, type) + strlen(opt_name) + 2);   dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
72   dest += sprintf(ret, "%s=", opt_name);   dest += sprintf(ret, "%s=", opt_name);
73    
74   for (;;) {   while (len >= optlen) {
75   switch (type) {   switch (type) {
76   case OPTION_IP_PAIR:   case OPTION_IP_PAIR:
77   dest += sprintip(dest, "", option);   dest += sprint_nip(dest, "", option);
78   *dest++ = '/';   *dest++ = '/';
79   option += 4;   option += 4;
80   optlen = 4;   optlen = 4;
81   case OPTION_IP: /* Works regardless of host byte order. */   case OPTION_IP: /* Works regardless of host byte order. */
82   dest += sprintip(dest, "", option);   dest += sprint_nip(dest, "", option);
83   break;   break;
84   case OPTION_BOOLEAN:   case OPTION_BOOLEAN:
85   dest += sprintf(dest, *option ? "yes" : "no");   dest += sprintf(dest, *option ? "yes" : "no");
# Line 90  static char *alloc_fill_opts(uint8_t *op Line 88  static char *alloc_fill_opts(uint8_t *op
88   dest += sprintf(dest, "%u", *option);   dest += sprintf(dest, "%u", *option);
89   break;   break;
90   case OPTION_U16:   case OPTION_U16:
91   memcpy(&val_u16, option, 2);   move_from_unaligned16(val_u16, option);
92   dest += sprintf(dest, "%u", ntohs(val_u16));   dest += sprintf(dest, "%u", ntohs(val_u16));
93   break;   break;
94   case OPTION_S16:   case OPTION_S16:
95   memcpy(&val_s16, option, 2);   move_from_unaligned16(val_s16, option);
96   dest += sprintf(dest, "%d", ntohs(val_s16));   dest += sprintf(dest, "%d", ntohs(val_s16));
97   break;   break;
98   case OPTION_U32:   case OPTION_U32:
99   memcpy(&val_u32, option, 4);   move_from_unaligned32(val_u32, option);
100   dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));   dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));
101   break;   break;
102   case OPTION_S32:   case OPTION_S32:
103   memcpy(&val_s32, option, 4);   move_from_unaligned32(val_s32, option);
104   dest += sprintf(dest, "%ld", (long) ntohl(val_s32));   dest += sprintf(dest, "%ld", (long) ntohl(val_s32));
105   break;   break;
106   case OPTION_STRING:   case OPTION_STRING:
107   memcpy(dest, option, len);   memcpy(dest, option, len);
108   dest[len] = '\0';   dest[len] = '\0';
109   return ret; /* Short circuit this case */   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  #if ENABLE_FEATURE_UDHCP_RFC3397
155   case OPTION_STR1035:   case OPTION_STR1035:
156   /* unpack option into dest; use ret for prefix (i.e., "optname=") */   /* unpack option into dest; use ret for prefix (i.e., "optname=") */
157   dest = dname_dec(option, len, ret);   dest = dname_dec(option, len, ret);
158   free(ret);   if (dest) {
159   return dest;   free(ret);
160     return dest;
161     }
162     /* error. return "optname=" string */
163     return ret;
164  #endif  #endif
165   }   }
166   option += optlen;   option += optlen;
167   len -= optlen;   len -= optlen;
168   if (len <= 0) break;   if (len <= 0)
169   dest += sprintf(dest, " ");   break;
170     *dest++ = ' ';
171     *dest = '\0';
172   }   }
173   return ret;   return ret;
174  }  }
175    
176    
177  /* put all the parameters into an environment */  /* put all the parameters into an environment */
178  static char **fill_envp(struct dhcpMessage *packet)  static char **fill_envp(struct dhcp_packet *packet)
179  {  {
180   int num_options = 0;   int num_options = 0;
181   int i, j;   int i;
182   char **envp;   char **envp, **curr;
  char *var;  
183   const char *opt_name;   const char *opt_name;
184   uint8_t *temp;   uint8_t *temp;
185   char over = 0;   uint8_t over = 0;
186    
187   if (packet) {   if (packet) {
188   for (i = 0; dhcp_options[i].code; i++) {   for (i = 0; dhcp_options[i].code; i++) {
# Line 145  static char **fill_envp(struct dhcpMessa Line 192  static char **fill_envp(struct dhcpMessa
192   num_options++; /* for mton */   num_options++; /* for mton */
193   }   }
194   }   }
195   if (packet->siaddr)   if (packet->siaddr_nip)
196   num_options++;   num_options++;
197   temp = get_option(packet, DHCP_OPTION_OVER);   temp = get_option(packet, DHCP_OPTION_OVERLOAD);
198   if (temp)   if (temp)
199   over = *temp;   over = *temp;
200   if (!(over & FILE_FIELD) && packet->file[0])   if (!(over & FILE_FIELD) && packet->file[0])
# Line 156  static char **fill_envp(struct dhcpMessa Line 203  static char **fill_envp(struct dhcpMessa
203   num_options++;   num_options++;
204   }   }
205    
206   envp = xzalloc(sizeof(char *) * (num_options + 5));   curr = envp = xzalloc(sizeof(char *) * (num_options + 3));
207   j = 0;   *curr = xasprintf("interface=%s", client_config.interface);
208   envp[j++] = xasprintf("interface=%s", client_config.interface);   putenv(*curr++);
  var = getenv("PATH");  
  if (var)  
  envp[j++] = xasprintf("PATH=%s", var);  
  var = getenv("HOME");  
  if (var)  
  envp[j++] = xasprintf("HOME=%s", var);  
209    
210   if (packet == NULL)   if (packet == NULL)
211   return envp;   return envp;
212    
213   envp[j] = xmalloc(sizeof("ip=255.255.255.255"));   *curr = xmalloc(sizeof("ip=255.255.255.255"));
214   sprintip(envp[j++], "ip=", (uint8_t *) &packet->yiaddr);   sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
215     putenv(*curr++);
216    
217   opt_name = dhcp_option_strings;   opt_name = dhcp_option_strings;
218   i = 0;   i = 0;
# Line 178  static char **fill_envp(struct dhcpMessa Line 220  static char **fill_envp(struct dhcpMessa
220   temp = get_option(packet, dhcp_options[i].code);   temp = get_option(packet, dhcp_options[i].code);
221   if (!temp)   if (!temp)
222   goto next;   goto next;
223   envp[j++] = alloc_fill_opts(temp, &dhcp_options[i], opt_name);   *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 */   /* Fill in a subnet bits option for things like /24 */
227   if (dhcp_options[i].code == DHCP_SUBNET) {   if (dhcp_options[i].code == DHCP_SUBNET) {
228   uint32_t subnet;   uint32_t subnet;
229   memcpy(&subnet, temp, 4);   move_from_unaligned32(subnet, temp);
230   envp[j++] = xasprintf("mask=%d", mton(subnet));   *curr = xasprintf("mask=%d", mton(subnet));
231     putenv(*curr++);
232   }   }
233   next:   next:
234   opt_name += strlen(opt_name) + 1;   opt_name += strlen(opt_name) + 1;
235   i++;   i++;
236   }   }
237   if (packet->siaddr) {   if (packet->siaddr_nip) {
238   envp[j] = xmalloc(sizeof("siaddr=255.255.255.255"));   *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
239   sprintip(envp[j++], "siaddr=", (uint8_t *) &packet->siaddr);   sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
240     putenv(*curr++);
241   }   }
242   if (!(over & FILE_FIELD) && packet->file[0]) {   if (!(over & FILE_FIELD) && packet->file[0]) {
243   /* watch out for invalid packets */   /* watch out for invalid packets */
244   packet->file[sizeof(packet->file) - 1] = '\0';   packet->file[sizeof(packet->file) - 1] = '\0';
245   envp[j++] = xasprintf("boot_file=%s", packet->file);   *curr = xasprintf("boot_file=%s", packet->file);
246     putenv(*curr++);
247   }   }
248   if (!(over & SNAME_FIELD) && packet->sname[0]) {   if (!(over & SNAME_FIELD) && packet->sname[0]) {
249   /* watch out for invalid packets */   /* watch out for invalid packets */
250   packet->sname[sizeof(packet->sname) - 1] = '\0';   packet->sname[sizeof(packet->sname) - 1] = '\0';
251   envp[j++] = xasprintf("sname=%s", packet->sname);   *curr = xasprintf("sname=%s", packet->sname);
252     putenv(*curr++);
253   }   }
254   return envp;   return envp;
255  }  }
256    
257    
258  /* Call a script with a par file and env vars */  /* Call a script with a par file and env vars */
259  void FAST_FUNC udhcp_run_script(struct dhcpMessage *packet, const char *name)  void FAST_FUNC udhcp_run_script(struct dhcp_packet *packet, const char *name)
260  {  {
  int pid;  
261   char **envp, **curr;   char **envp, **curr;
262     char *argv[3];
263    
264   if (client_config.script == NULL)   if (client_config.script == NULL)
265   return;   return;
266    
  DEBUG("vfork'ing and execle'ing %s", client_config.script);  
   
267   envp = fill_envp(packet);   envp = fill_envp(packet);
268    
269   /* call script */   /* call script */
270  // can we use wait4pid(spawn(...)) here?   log1("Executing %s %s", client_config.script, name);
271   pid = vfork();   argv[0] = (char*) client_config.script;
272   if (pid < 0) return;   argv[1] = (char*) name;
273   if (pid == 0) {   argv[2] = NULL;
274   /* close fd's? */   wait4pid(spawn(argv));
275   /* exec script */  
276   execle(client_config.script, client_config.script,   for (curr = envp; *curr; curr++) {
277         name, NULL, envp);   log2(" %s", *curr);
278   bb_perror_msg_and_die("exec %s", client_config.script);   bb_unsetenv(*curr);
  }  
  safe_waitpid(pid, NULL, 0);  
  for (curr = envp; *curr; curr++)  
279   free(*curr);   free(*curr);
280     }
281   free(envp);   free(envp);
282  }  }

Legend:
Removed from v.983  
changed lines
  Added in v.984