Magellan Linux

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

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

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 11  Line 11 
11  #include "options.h"  #include "options.h"
12    
13    
14  /*  /* on these functions, make sure your datatype matches */
  * Domain names may have 254 chars, and string options can be 254  
  * chars long. However, 80 bytes will be enough for most, and won't  
  * hog up memory. If you have a special application, change it  
  */  
 #define READ_CONFIG_BUF_SIZE 80  
   
 /* on these functions, make sure you datatype matches */  
15  static int read_ip(const char *line, void *arg)  static int read_ip(const char *line, void *arg)
16  {  {
17   struct in_addr *addr = arg;   len_and_sockaddr *lsa;
18   struct hostent *host;  
19   int retval = 1;   lsa = host_and_af2sockaddr(line, 0, AF_INET);
20     if (!lsa)
21   if (!inet_aton(line, addr)) {   return 0;
22   host = gethostbyname(line);   *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr;
23   if (host)   free(lsa);
24   addr->s_addr = *((unsigned long *) host->h_addr_list[0]);   return 1;
  else retval = 0;  
  }  
  return retval;  
25  }  }
26    
27  static int read_mac(const char *line, void *arg)  static int read_mac(const char *line, void *arg)
28  {  {
  uint8_t *mac_bytes = arg;  
29   struct ether_addr *temp_ether_addr;   struct ether_addr *temp_ether_addr;
  int retval = 1;  
   
  temp_ether_addr = ether_aton(line);  
30    
31     temp_ether_addr = ether_aton_r(line, (struct ether_addr *)arg);
32   if (temp_ether_addr == NULL)   if (temp_ether_addr == NULL)
33   retval = 0;   return 0;
34   else   return 1;
  memcpy(mac_bytes, temp_ether_addr, 6);  
   
  return retval;  
35  }  }
36    
37    
# Line 57  static int read_str(const char *line, vo Line 41  static int read_str(const char *line, vo
41    
42   free(*dest);   free(*dest);
43   *dest = xstrdup(line);   *dest = xstrdup(line);
   
44   return 1;   return 1;
45  }  }
46    
47    
48  static int read_u32(const char *line, void *arg)  static int read_u32(const char *line, void *arg)
49  {  {
50   *((uint32_t*)arg) = bb_strtou32(line, NULL, 10);   *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
51   return errno == 0;   return errno == 0;
52  }  }
53    
# Line 72  static int read_u32(const char *line, vo Line 55  static int read_u32(const char *line, vo
55  static int read_yn(const char *line, void *arg)  static int read_yn(const char *line, void *arg)
56  {  {
57   char *dest = arg;   char *dest = arg;
  int retval = 1;  
58    
59   if (!strcasecmp("yes", line))   if (!strcasecmp("yes", line)) {
60   *dest = 1;   *dest = 1;
61   else if (!strcasecmp("no", line))   return 1;
62     }
63     if (!strcasecmp("no", line)) {
64   *dest = 0;   *dest = 0;
65   else retval = 0;   return 1;
66     }
67   return retval;   return 0;
68  }  }
69    
70    
71  /* find option 'code' in opt_list */  /* find option 'code' in opt_list */
72  struct option_set *find_option(struct option_set *opt_list, char code)  struct option_set* FAST_FUNC find_option(struct option_set *opt_list, uint8_t code)
73  {  {
74   while (opt_list && opt_list->data[OPT_CODE] < code)   while (opt_list && opt_list->data[OPT_CODE] < code)
75   opt_list = opt_list->next;   opt_list = opt_list->next;
76    
77   if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;   if (opt_list && opt_list->data[OPT_CODE] == code)
78   else return NULL;   return opt_list;
79     return NULL;
80  }  }
81    
82    
# Line 101  static void attach_option(struct option_ Line 86  static void attach_option(struct option_
86  {  {
87   struct option_set *existing, *new, **curr;   struct option_set *existing, *new, **curr;
88    
  /* add it to an existing option */  
89   existing = find_option(*opt_list, option->code);   existing = find_option(*opt_list, option->code);
90   if (existing) {   if (!existing) {
91   DEBUG("Attaching option %s to existing member of list", option->name);   DEBUG("Attaching option %02x to list", option->code);
92   if (option->flags & OPTION_LIST) {  
93   if (existing->data[OPT_LEN] + length <= 255) {  #if ENABLE_FEATURE_UDHCP_RFC3397
94   existing->data = realloc(existing->data,   if ((option->flags & TYPE_MASK) == OPTION_STR1035)
95   existing->data[OPT_LEN] + length + 2);   /* reuse buffer and length for RFC1035-formatted string */
96   memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);   buffer = (char *)dname_enc(NULL, 0, buffer, &length);
97   existing->data[OPT_LEN] += length;  #endif
  } /* else, ignore the data, we could put this in a second option in the future */  
  } /* else, ignore the new data */  
  } else {  
  DEBUG("Attaching option %s to list", option->name);  
98    
99   /* make a new option */   /* make a new option */
100   new = xmalloc(sizeof(struct option_set));   new = xmalloc(sizeof(*new));
101   new->data = xmalloc(length + 2);   new->data = xmalloc(length + 2);
102   new->data[OPT_CODE] = option->code;   new->data[OPT_CODE] = option->code;
103   new->data[OPT_LEN] = length;   new->data[OPT_LEN] = length;
# Line 129  static void attach_option(struct option_ Line 109  static void attach_option(struct option_
109    
110   new->next = *curr;   new->next = *curr;
111   *curr = new;   *curr = new;
112    #if ENABLE_FEATURE_UDHCP_RFC3397
113     if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
114     free(buffer);
115    #endif
116     return;
117   }   }
118    
119     /* add it to an existing option */
120     DEBUG("Attaching option %02x to existing member of list", option->code);
121     if (option->flags & OPTION_LIST) {
122    #if ENABLE_FEATURE_UDHCP_RFC3397
123     if ((option->flags & TYPE_MASK) == OPTION_STR1035)
124     /* reuse buffer and length for RFC1035-formatted string */
125     buffer = (char *)dname_enc(existing->data + 2,
126     existing->data[OPT_LEN], buffer, &length);
127    #endif
128     if (existing->data[OPT_LEN] + length <= 255) {
129     existing->data = xrealloc(existing->data,
130     existing->data[OPT_LEN] + length + 3);
131     if ((option->flags & TYPE_MASK) == OPTION_STRING) {
132     /* ' ' can bring us to 256 - bad */
133     if (existing->data[OPT_LEN] + length >= 255)
134     return;
135     /* add space separator between STRING options in a list */
136     existing->data[existing->data[OPT_LEN] + 2] = ' ';
137     existing->data[OPT_LEN]++;
138     }
139     memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
140     existing->data[OPT_LEN] += length;
141     } /* else, ignore the data, we could put this in a second option in the future */
142    #if ENABLE_FEATURE_UDHCP_RFC3397
143     if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
144     free(buffer);
145    #endif
146     } /* else, ignore the new data */
147  }  }
148    
149    
# Line 138  static int read_opt(const char *const_li Line 152  static int read_opt(const char *const_li
152  {  {
153   struct option_set **opt_list = arg;   struct option_set **opt_list = arg;
154   char *opt, *val, *endptr;   char *opt, *val, *endptr;
  const struct dhcp_option *option;  
  int retval = 0, length;  
  char buffer[8];  
155   char *line;   char *line;
156     const struct dhcp_option *option;
157     int retval, length, idx;
158     char buffer[8] ALIGNED(4);
159   uint16_t *result_u16 = (uint16_t *) buffer;   uint16_t *result_u16 = (uint16_t *) buffer;
160   uint32_t *result_u32 = (uint32_t *) buffer;   uint32_t *result_u32 = (uint32_t *) buffer;
161    
162   /* Cheat, the only const line we'll actually get is "" */   /* Cheat, the only const line we'll actually get is "" */
163   line = (char *) const_line;   line = (char *) const_line;
164   opt = strtok(line, " \t=");   opt = strtok(line, " \t=");
165   if (!opt) return 0;   if (!opt)
166     return 0;
167    
168   option = dhcp_options;   idx = index_in_strings(dhcp_option_strings, opt); /* NB: was strcasecmp! */
169   while (1) {   if (idx < 0)
170   if (!option->code)   return 0;
171   return 0;   option = &dhcp_options[idx];
  if (!strcasecmp(option->name, opt))  
  break;  
  option++;  
  }  
172    
173     retval = 0;
174   do {   do {
175   val = strtok(NULL, ", \t");   val = strtok(NULL, ", \t");
176   if (!val) break;   if (!val) break;
177   length = option_lengths[option->flags & TYPE_MASK];   length = dhcp_option_lengths[option->flags & TYPE_MASK];
178   retval = 0;   retval = 0;
179   opt = buffer; /* new meaning for variable opt */   opt = buffer; /* new meaning for variable opt */
180   switch (option->flags & TYPE_MASK) {   switch (option->flags & TYPE_MASK) {
# Line 171  static int read_opt(const char *const_li Line 183  static int read_opt(const char *const_li
183   break;   break;
184   case OPTION_IP_PAIR:   case OPTION_IP_PAIR:
185   retval = read_ip(val, buffer);   retval = read_ip(val, buffer);
186   if (!(val = strtok(NULL, ", \t/-"))) retval = 0;   val = strtok(NULL, ", \t/-");
187   if (retval) retval = read_ip(val, buffer + 4);   if (!val)
188     retval = 0;
189     if (retval)
190     retval = read_ip(val, buffer + 4);
191   break;   break;
192   case OPTION_STRING:   case OPTION_STRING:
193    #if ENABLE_FEATURE_UDHCP_RFC3397
194     case OPTION_STR1035:
195    #endif
196   length = strlen(val);   length = strlen(val);
197   if (length > 0) {   if (length > 0) {
198   if (length > 254) length = 254;   if (length > 254) length = 254;
# Line 189  static int read_opt(const char *const_li Line 207  static int read_opt(const char *const_li
207   buffer[0] = strtoul(val, &endptr, 0);   buffer[0] = strtoul(val, &endptr, 0);
208   retval = (endptr[0] == '\0');   retval = (endptr[0] == '\0');
209   break;   break;
210   case OPTION_U16:   /* htonX are macros in older libc's, using temp var
211   *result_u16 = htons(strtoul(val, &endptr, 0));   * in code below for safety */
212   retval = (endptr[0] == '\0');   /* TODO: use bb_strtoX? */
213     case OPTION_U16: {
214     unsigned long tmp = strtoul(val, &endptr, 0);
215     *result_u16 = htons(tmp);
216     retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/);
217   break;   break;
218   case OPTION_S16:   }
219   *result_u16 = htons(strtol(val, &endptr, 0));   case OPTION_S16: {
220     long tmp = strtol(val, &endptr, 0);
221     *result_u16 = htons(tmp);
222   retval = (endptr[0] == '\0');   retval = (endptr[0] == '\0');
223   break;   break;
224   case OPTION_U32:   }
225   *result_u32 = htonl(strtoul(val, &endptr, 0));   case OPTION_U32: {
226     unsigned long tmp = strtoul(val, &endptr, 0);
227     *result_u32 = htonl(tmp);
228   retval = (endptr[0] == '\0');   retval = (endptr[0] == '\0');
229   break;   break;
230   case OPTION_S32:   }
231   *result_u32 = htonl(strtol(val, &endptr, 0));   case OPTION_S32: {
232     long tmp = strtol(val, &endptr, 0);
233     *result_u32 = htonl(tmp);
234   retval = (endptr[0] == '\0');   retval = (endptr[0] == '\0');
235   break;   break;
236     }
237   default:   default:
238   break;   break;
239   }   }
# Line 222  static int read_staticlease(const char * Line 251  static int read_staticlease(const char *
251   uint8_t *mac_bytes;   uint8_t *mac_bytes;
252   uint32_t *ip;   uint32_t *ip;
253    
   
254   /* Allocate memory for addresses */   /* Allocate memory for addresses */
255   mac_bytes = xmalloc(sizeof(unsigned char) * 8);   mac_bytes = xmalloc(sizeof(unsigned char) * 8);
256   ip = xmalloc(sizeof(uint32_t));   ip = xmalloc(sizeof(uint32_t));
# Line 238  static int read_staticlease(const char * Line 266  static int read_staticlease(const char *
266    
267   addStaticLease(arg, mac_bytes, ip);   addStaticLease(arg, mac_bytes, ip);
268    
269   if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg);   if (ENABLE_UDHCP_DEBUG) printStaticLeases(arg);
270    
271   return 1;   return 1;
272  }  }
273    
274    
275  static const struct config_keyword keywords[] = {  struct config_keyword {
276   /* keyword handler   variable address default */   const char *keyword;
277   {"start", read_ip,  &(server_config.start), "192.168.0.20"},   int (*handler)(const char *line, void *var);
278   {"end", read_ip,  &(server_config.end), "192.168.0.254"},   void *var;
279   {"interface", read_str, &(server_config.interface), "eth0"},   const char *def;
  {"option", read_opt, &(server_config.options), ""},  
  {"opt", read_opt, &(server_config.options), ""},  
  {"max_leases", read_u32, &(server_config.max_leases), "254"},  
  {"remaining", read_yn,  &(server_config.remaining), "yes"},  
  {"auto_time", read_u32, &(server_config.auto_time), "7200"},  
  {"decline_time",read_u32, &(server_config.decline_time),"3600"},  
  {"conflict_time",read_u32,&(server_config.conflict_time),"3600"},  
  {"offer_time", read_u32, &(server_config.offer_time), "60"},  
  {"min_lease", read_u32, &(server_config.min_lease), "60"},  
  {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE},  
  {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"},  
  {"notify_file", read_str, &(server_config.notify_file), ""},  
  {"siaddr", read_ip,  &(server_config.siaddr), "0.0.0.0"},  
  {"sname", read_str, &(server_config.sname), ""},  
  {"boot_file", read_str, &(server_config.boot_file), ""},  
  {"static_lease",read_staticlease, &(server_config.static_leases), ""},  
  /*ADDME: static lease */  
  {"", NULL,  NULL, ""}  
280  };  };
281    
282    static const struct config_keyword keywords[] = {
283     /* keyword       handler   variable address               default */
284     {"start",        read_ip,  &(server_config.start_ip),     "192.168.0.20"},
285     {"end",          read_ip,  &(server_config.end_ip),       "192.168.0.254"},
286     {"interface",    read_str, &(server_config.interface),    "eth0"},
287     /* Avoid "max_leases value not sane" warning by setting default
288     * to default_end_ip - default_start_ip + 1: */
289     {"max_leases",   read_u32, &(server_config.max_leases),   "235"},
290     {"remaining",    read_yn,  &(server_config.remaining),    "yes"},
291     {"auto_time",    read_u32, &(server_config.auto_time),    "7200"},
292     {"decline_time", read_u32, &(server_config.decline_time), "3600"},
293     {"conflict_time",read_u32, &(server_config.conflict_time),"3600"},
294     {"offer_time",   read_u32, &(server_config.offer_time),   "60"},
295     {"min_lease",    read_u32, &(server_config.min_lease),    "60"},
296     {"lease_file",   read_str, &(server_config.lease_file),   LEASES_FILE},
297     {"pidfile",      read_str, &(server_config.pidfile),      "/var/run/udhcpd.pid"},
298     {"siaddr",       read_ip,  &(server_config.siaddr),       "0.0.0.0"},
299     /* keywords with no defaults must be last! */
300     {"option",       read_opt, &(server_config.options),      ""},
301     {"opt",          read_opt, &(server_config.options),      ""},
302     {"notify_file",  read_str, &(server_config.notify_file),  ""},
303     {"sname",        read_str, &(server_config.sname),        ""},
304     {"boot_file",    read_str, &(server_config.boot_file),    ""},
305     {"static_lease", read_staticlease, &(server_config.static_leases), ""},
306     /* ADDME: static lease */
307    };
308    enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
309    
310  int read_config(const char *file)  void FAST_FUNC read_config(const char *file)
311  {  {
312   FILE *in;   parser_t *parser;
313   char buffer[READ_CONFIG_BUF_SIZE], *token, *line;   const struct config_keyword *k;
314   int i, lm = 0;   unsigned i;
315     char *token[2];
316   for (i = 0; keywords[i].keyword[0]; i++)  
317   if (keywords[i].def[0])   for (i = 0; i < KWS_WITH_DEFAULTS; i++)
318   keywords[i].handler(keywords[i].def, keywords[i].var);   keywords[i].handler(keywords[i].def, keywords[i].var);
   
  in = fopen(file, "r");  
  if (!in) {  
  bb_error_msg("cannot open config file: %s", file);  
  return 0;  
  }  
319    
320   while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {   parser = config_open(file);
321   char debug_orig[READ_CONFIG_BUF_SIZE];   while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
322   char *p;   for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
323     if (!strcasecmp(token[0], k->keyword)) {
324   lm++;   if (!k->handler(token[1], k->var)) {
325   p = strchr(buffer, '\n');   bb_error_msg("can't parse line %u in %s",
326   if (p) *p = '\0';   parser->lineno, file);
  if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer);  
  p = strchr(buffer, '#');  
  if (p) *p = '\0';  
   
  if (!(token = strtok(buffer, " \t"))) continue;  
  if (!(line = strtok(NULL, ""))) continue;  
   
  /* eat leading whitespace */  
  line = skip_whitespace(line);  
  /* eat trailing whitespace */  
  i = strlen(line) - 1;  
  while (i >= 0 && isspace(line[i]))  
  line[i--] = '\0';  
   
  for (i = 0; keywords[i].keyword[0]; i++)  
  if (!strcasecmp(token, keywords[i].keyword))  
  if (!keywords[i].handler(line, keywords[i].var)) {  
  bb_error_msg("cannot parse line %d of %s", lm, file);  
  if (ENABLE_FEATURE_UDHCP_DEBUG)  
  bb_error_msg("cannot parse '%s'", debug_orig);  
327   /* reset back to the default value */   /* reset back to the default value */
328   keywords[i].handler(keywords[i].def, keywords[i].var);   k->handler(k->def, k->var);
329   }   }
330     break;
331     }
332     }
333   }   }
334   fclose(in);   config_close(parser);
335   return 1;  
336     server_config.start_ip = ntohl(server_config.start_ip);
337     server_config.end_ip = ntohl(server_config.end_ip);
338  }  }
339    
340    
341  void write_leases(void)  void FAST_FUNC write_leases(void)
342  {  {
343   int fp;   int fp;
344   unsigned i;   unsigned i;
345   time_t curr = time(0);   time_t curr = time(0);
346   unsigned long tmp_time;   unsigned long tmp_time;
347    
348   fp = open(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);   fp = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
349   if (fp < 0) {   if (fp < 0) {
  bb_error_msg("cannot open %s for writing", server_config.lease_file);  
350   return;   return;
351   }   }
352    
# Line 357  void write_leases(void) Line 372  void write_leases(void)
372   close(fp);   close(fp);
373    
374   if (server_config.notify_file) {   if (server_config.notify_file) {
375    // TODO: vfork-based child creation
376   char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file);   char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file);
377   system(cmd);   system(cmd);
378   free(cmd);   free(cmd);
# Line 364  void write_leases(void) Line 380  void write_leases(void)
380  }  }
381    
382    
383  void read_leases(const char *file)  void FAST_FUNC read_leases(const char *file)
384  {  {
385   int fp;   int fp;
386   unsigned int i = 0;   unsigned i;
387   struct dhcpOfferedAddr lease;   struct dhcpOfferedAddr lease;
388    
389   fp = open(file, O_RDONLY);   fp = open_or_warn(file, O_RDONLY);
390   if (fp < 0) {   if (fp < 0) {
  bb_error_msg("cannot open %s for reading", file);  
391   return;   return;
392   }   }
393    
394     i = 0;
395   while (i < server_config.max_leases   while (i < server_config.max_leases
396   && full_read(fp, &lease, sizeof(lease)) == sizeof(lease)   && full_read(fp, &lease, sizeof(lease)) == sizeof(lease)
397   ) {   ) {
398   /* ADDME: is it a static lease */   /* ADDME: is it a static lease */
399   if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) {   uint32_t y = ntohl(lease.yiaddr);
400     if (y >= server_config.start_ip && y <= server_config.end_ip) {
401   lease.expires = ntohl(lease.expires);   lease.expires = ntohl(lease.expires);
402   if (!server_config.remaining) lease.expires -= time(0);   if (!server_config.remaining)
403     lease.expires -= time(NULL);
404   if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {   if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
405   bb_error_msg("too many leases while loading %s", file);   bb_error_msg("too many leases while loading %s", file);
406   break;   break;

Legend:
Removed from v.532  
changed lines
  Added in v.816