xtoptions.c revision 2e0ec4fa0fb5162c441cd666f55fe76777e40d5e
130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/* 230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Argument parser 330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Copyright © Jan Engelhardt, 2011 430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * This program is free software; you can redistribute it and/or 630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * modify it under the terms of the GNU General Public License as 730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * published by the Free Software Foundation; either version 2 of 830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * the License, or (at your option) any later version. 930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */ 1030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <ctype.h> 1130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <errno.h> 1230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <getopt.h> 1330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <limits.h> 1430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <netdb.h> 1530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <stdbool.h> 1630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <stdint.h> 1730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <stdio.h> 1830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <stdlib.h> 1930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <string.h> 2030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <arpa/inet.h> 2130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "xtables.h" 2230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "xshared.h" 2330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 2430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#define XTOPT_MKPTR(cb) \ 2530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ((void *)((char *)(cb)->data + (cb)->entry->ptroff)) 2630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 2730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/** 2830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Creates getopt options from the x6-style option map, and assigns each a 2930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * getopt id. 3030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */ 3130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunstruct option * 3230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunxtables_options_xfrm(struct option *orig_opts, struct option *oldopts, 3330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun const struct xt_option_entry *entry, unsigned int *offset) 3430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun{ 3530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun unsigned int num_orig, num_old = 0, num_new, i; 3630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun struct option *merge, *mp; 3730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 3830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (entry == NULL) 3930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return oldopts; 4030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig) 4130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ; 4230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (oldopts != NULL) 4330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun for (num_old = 0; oldopts[num_old].name != NULL; ++num_old) 4430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ; 4530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun for (num_new = 0; entry[num_new].name != NULL; ++num_new) 4630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ; 4730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 4830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun /* 4930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Since @oldopts also has @orig_opts already (and does so at the 5030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * start), skip these entries. 5130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */ 5230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun oldopts += num_orig; 5330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun num_old -= num_orig; 54 55 merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1)); 56 if (merge == NULL) 57 return NULL; 58 59 /* Let the base options -[ADI...] have precedence over everything */ 60 memcpy(merge, orig_opts, sizeof(*mp) * num_orig); 61 mp = merge + num_orig; 62 63 /* Second, the new options */ 64 xt_params->option_offset += XT_OPTION_OFFSET_SCALE; 65 *offset = xt_params->option_offset; 66 67 for (i = 0; i < num_new; ++i, ++mp, ++entry) { 68 mp->name = entry->name; 69 mp->has_arg = entry->type != XTTYPE_NONE; 70 mp->flag = NULL; 71 mp->val = entry->id + *offset; 72 } 73 74 /* Third, the old options */ 75 memcpy(mp, oldopts, sizeof(*mp) * num_old); 76 mp += num_old; 77 xtables_free_opts(0); 78 79 /* Clear trailing entry */ 80 memset(mp, 0, sizeof(*mp)); 81 return merge; 82} 83 84/** 85 * Require a simple integer. 86 */ 87static void xtopt_parse_int(struct xt_option_call *cb) 88{ 89 const struct xt_option_entry *entry = cb->entry; 90 unsigned long long lmin = 0, lmax = UINT32_MAX; 91 unsigned int value; 92 93 if (entry->type == XTTYPE_UINT8) 94 lmax = UINT8_MAX; 95 else if (entry->type == XTTYPE_UINT64) 96 lmax = UINT64_MAX; 97 if (cb->entry->min != 0) 98 lmin = cb->entry->min; 99 if (cb->entry->max != 0) 100 lmax = cb->entry->max; 101 102 if (!xtables_strtoui(cb->arg, NULL, &value, lmin, lmax)) 103 xt_params->exit_err(PARAMETER_PROBLEM, 104 "%s: bad value for option \"--%s\", " 105 "or out of range (%llu-%llu).\n", 106 cb->ext_name, entry->name, lmin, lmax); 107 108 if (entry->type == XTTYPE_UINT8) { 109 cb->val.u8 = value; 110 if (entry->flags & XTOPT_PUT) 111 *(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8; 112 } else if (entry->type == XTTYPE_UINT32) { 113 cb->val.u32 = value; 114 if (entry->flags & XTOPT_PUT) 115 *(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32; 116 } else if (entry->type == XTTYPE_UINT64) { 117 cb->val.u64 = value; 118 if (entry->flags & XTOPT_PUT) 119 *(uint64_t *)XTOPT_MKPTR(cb) = cb->val.u64; 120 } 121} 122 123/** 124 * Multiple integer parse routine. 125 * 126 * This function is capable of parsing any number of fields. Only the first 127 * two values from the string will be put into @cb however (and as such, 128 * @cb->val.uXX_range is just that large) to cater for the few extensions that 129 * do not have a range[2] field, but {min, max}, and which cannot use 130 * XTOPT_POINTER. 131 */ 132static void xtopt_parse_mint(struct xt_option_call *cb) 133{ 134 const struct xt_option_entry *entry = cb->entry; 135 const char *arg = cb->arg; 136 uint32_t *put = XTOPT_MKPTR(cb); 137 unsigned int maxiter, value; 138 char *end = ""; 139 char sep = ':'; 140 141 maxiter = entry->size / sizeof(uint32_t); 142 if (maxiter == 0) 143 maxiter = 2; /* ARRAY_SIZE(cb->val.uXX_range) */ 144 if (entry->size % sizeof(uint32_t) != 0) 145 xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does " 146 "not have proper size\n", __func__); 147 148 cb->nvals = 0; 149 for (arg = cb->arg; ; arg = end + 1) { 150 if (cb->nvals == maxiter) 151 xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many " 152 "components for option \"--%s\" (max: %u)\n", 153 cb->ext_name, entry->name, maxiter); 154 if (!xtables_strtoui(arg, &end, &value, 0, UINT32_MAX)) 155 xt_params->exit_err(PARAMETER_PROBLEM, 156 "%s: bad value for option \"--%s\", " 157 "or out of range (0-%u).\n", 158 cb->ext_name, entry->name, UINT32_MAX); 159 if (*end != '\0' && *end != sep) 160 xt_params->exit_err(PARAMETER_PROBLEM, 161 "%s: Argument to \"--%s\" has unexpected " 162 "characters.\n", cb->ext_name, entry->name); 163 ++cb->nvals; 164 if (cb->nvals < ARRAY_SIZE(cb->val.u32_range)) 165 cb->val.u32_range[cb->nvals] = value; 166 if (entry->flags & XTOPT_PUT) 167 *put++ = value; 168 if (*end == '\0') 169 break; 170 } 171} 172 173static void xtopt_parse_string(struct xt_option_call *cb) 174{ 175 const struct xt_option_entry *entry = cb->entry; 176 size_t z = strlen(cb->arg); 177 char *p; 178 179 if (entry->min != 0 && z < entry->min) 180 xt_params->exit_err(PARAMETER_PROBLEM, 181 "Argument must have a minimum length of " 182 "%u characters\n", entry->min); 183 if (entry->max != 0 && z > entry->max) 184 xt_params->exit_err(PARAMETER_PROBLEM, 185 "Argument must have a maximum length of " 186 "%u characters\n", entry->max); 187 if (!(entry->flags & XTOPT_PUT)) 188 return; 189 if (z >= entry->size) 190 z = entry->size - 1; 191 p = XTOPT_MKPTR(cb); 192 strncpy(p, cb->arg, z); 193 p[z] = '\0'; 194} 195 196/** 197 * Validate the input for being conformant to "mark[/mask]". 198 */ 199static void xtopt_parse_markmask(struct xt_option_call *cb) 200{ 201 unsigned int mark = 0, mask = ~0U; 202 char *end; 203 204 if (!xtables_strtoui(cb->arg, &end, &mark, 0, UINT32_MAX)) 205 xt_params->exit_err(PARAMETER_PROBLEM, 206 "%s: bad mark value for option \"--%s\", " 207 "or out of range.\n", 208 cb->ext_name, cb->entry->name); 209 if (*end == '/' && 210 !xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 211 xt_params->exit_err(PARAMETER_PROBLEM, 212 "%s: bad mask value for option \"--%s\", " 213 "or out of range.\n", 214 cb->ext_name, cb->entry->name); 215 if (*end != '\0') 216 xt_params->exit_err(PARAMETER_PROBLEM, 217 "%s: trailing garbage after value " 218 "for option \"--%s\".\n", 219 cb->ext_name, cb->entry->name); 220 cb->val.mark = mark; 221 cb->val.mask = mask; 222} 223 224static void (*const xtopt_subparse[])(struct xt_option_call *) = { 225 [XTTYPE_UINT8] = xtopt_parse_int, 226 [XTTYPE_UINT32] = xtopt_parse_int, 227 [XTTYPE_UINT64] = xtopt_parse_int, 228 [XTTYPE_UINT32RC] = xtopt_parse_mint, 229 [XTTYPE_STRING] = xtopt_parse_string, 230 [XTTYPE_MARKMASK32] = xtopt_parse_markmask, 231}; 232 233static const size_t xtopt_psize[] = { 234 [XTTYPE_UINT8] = sizeof(uint8_t), 235 [XTTYPE_UINT32] = sizeof(uint32_t), 236 [XTTYPE_UINT64] = sizeof(uint64_t), 237 [XTTYPE_UINT32RC] = sizeof(uint32_t[2]), 238 [XTTYPE_STRING] = -1, 239}; 240 241/** 242 * The master option parsing routine. May be used for the ".x6_parse" 243 * function pointer in extensions if fully automatic parsing is desired. 244 * It may be also called manually from a custom x6_parse function. 245 */ 246void xtables_option_parse(struct xt_option_call *cb) 247{ 248 const struct xt_option_entry *entry = cb->entry; 249 unsigned int eflag = 1 << cb->entry->id; 250 251 /* 252 * With {.id = P_FOO, .excl = P_FOO} we can have simple double-use 253 * prevention. Though it turned out that this is too much typing (most 254 * of the options are one-time use only), so now we also have 255 * %XTOPT_MULTI. 256 */ 257 if ((!(entry->flags & XTOPT_MULTI) || (entry->excl & eflag)) && 258 cb->xflags & eflag) 259 xt_params->exit_err(PARAMETER_PROBLEM, 260 "%s: option \"--%s\" can only be used once.\n", 261 cb->ext_name, cb->entry->name); 262 if (cb->invert && !(entry->flags & XTOPT_INVERT)) 263 xt_params->exit_err(PARAMETER_PROBLEM, 264 "%s: option \"--%s\" cannot be inverted.\n", 265 cb->ext_name, entry->name); 266 if (entry->type != XTTYPE_NONE && optarg == NULL) 267 xt_params->exit_err(PARAMETER_PROBLEM, 268 "%s: option \"--%s\" requires an argument.\n", 269 cb->ext_name, entry->name); 270 if (entry->type <= ARRAY_SIZE(xtopt_subparse) && 271 xtopt_subparse[entry->type] != NULL) 272 xtopt_subparse[entry->type](cb); 273 /* Exclusion with other flags tested later in finalize. */ 274 cb->xflags |= 1 << entry->id; 275} 276 277/** 278 * Verifies that an extension's option map descriptor is valid, and ought to 279 * be called right after the extension has been loaded, and before option 280 * merging/xfrm. 281 */ 282void xtables_option_metavalidate(const char *name, 283 const struct xt_option_entry *entry) 284{ 285 for (; entry->name != NULL; ++entry) { 286 if (entry->id >= CHAR_BIT * sizeof(unsigned int) || 287 entry->id >= XT_OPTION_OFFSET_SCALE) 288 xt_params->exit_err(OTHER_PROBLEM, 289 "Extension %s uses invalid ID %u\n", 290 name, entry->id); 291 if (!(entry->flags & XTOPT_PUT)) 292 continue; 293 if (entry->type >= ARRAY_SIZE(xtopt_psize)) 294 xt_params->exit_err(OTHER_PROBLEM, 295 "%s: entry type of option \"--%s\" cannot be " 296 "combined with XTOPT_PUT\n", 297 name, entry->name); 298 if (xtopt_psize[entry->type] != -1 && 299 xtopt_psize[entry->type] != entry->size) 300 xt_params->exit_err(OTHER_PROBLEM, 301 "%s: option \"--%s\" points to a memory block " 302 "of wrong size (expected %zu, got %zu)\n", 303 name, entry->name, 304 xtopt_psize[entry->type], entry->size); 305 } 306} 307 308/** 309 * Find an option entry by its id. 310 */ 311static const struct xt_option_entry * 312xtables_option_lookup(const struct xt_option_entry *entry, unsigned int id) 313{ 314 for (; entry->name != NULL; ++entry) 315 if (entry->id == id) 316 return entry; 317 return NULL; 318} 319 320/** 321 * @c: getopt id (i.e. with offset) 322 * @fw: struct ipt_entry or ip6t_entry 323 * 324 * Dispatch arguments to the appropriate parse function, based upon the 325 * extension's choice of API. 326 */ 327void xtables_option_tpcall(unsigned int c, char **argv, bool invert, 328 struct xtables_target *t, void *fw) 329{ 330 struct xt_option_call cb; 331 332 if (t->x6_parse == NULL) { 333 if (t->parse != NULL) 334 t->parse(c - t->option_offset, argv, invert, 335 &t->tflags, fw, &t->t); 336 return; 337 } 338 339 c -= t->option_offset; 340 cb.entry = xtables_option_lookup(t->x6_options, c); 341 if (cb.entry == NULL) 342 xtables_error(OTHER_PROBLEM, 343 "Extension does not know id %u\n", c); 344 cb.arg = optarg; 345 cb.invert = invert; 346 cb.ext_name = t->name; 347 cb.data = t->t->data; 348 cb.xflags = t->tflags; 349 t->x6_parse(&cb); 350 t->tflags = cb.xflags; 351} 352 353/** 354 * @c: getopt id (i.e. with offset) 355 * @fw: struct ipt_entry or ip6t_entry 356 * 357 * Dispatch arguments to the appropriate parse function, based upon the 358 * extension's choice of API. 359 */ 360void xtables_option_mpcall(unsigned int c, char **argv, bool invert, 361 struct xtables_match *m, void *fw) 362{ 363 struct xt_option_call cb; 364 365 if (m->x6_parse == NULL) { 366 if (m->parse != NULL) 367 m->parse(c - m->option_offset, argv, invert, 368 &m->mflags, fw, &m->m); 369 return; 370 } 371 372 c -= m->option_offset; 373 cb.entry = xtables_option_lookup(m->x6_options, c); 374 if (cb.entry == NULL) 375 xtables_error(OTHER_PROBLEM, 376 "Extension does not know id %u\n", c); 377 cb.arg = optarg; 378 cb.invert = invert; 379 cb.ext_name = m->name; 380 cb.data = m->m->data; 381 cb.xflags = m->mflags; 382 m->x6_parse(&cb); 383 m->mflags = cb.xflags; 384} 385 386/** 387 * @name: name of extension 388 * @entry: current option (from all ext's entries) being validated 389 * @xflags: flags the extension has collected 390 * @i: conflicting option (id) to test for 391 */ 392static void 393xtables_option_fcheck2(const char *name, const struct xt_option_entry *entry, 394 const struct xt_option_entry *other, 395 unsigned int xflags) 396{ 397 unsigned int ef = 1 << entry->id, of = 1 << other->id; 398 399 if (entry->also & of && !(xflags & of)) 400 xt_params->exit_err(PARAMETER_PROBLEM, 401 "%s: option \"--%s\" also requires \"--%s\".\n", 402 name, entry->name, other->name); 403 404 if (!(entry->excl & of)) 405 /* Use of entry does not collide with other option, good. */ 406 return; 407 if ((xflags & (ef | of)) != (ef | of)) 408 /* Conflicting options were not used. */ 409 return; 410 411 xt_params->exit_err(PARAMETER_PROBLEM, 412 "%s: option \"--%s\" cannot be used together with \"--%s\".\n", 413 name, entry->name, other->name); 414} 415 416/** 417 * @name: name of extension 418 * @xflags: accumulated flags 419 * @entry: extension's option table 420 * 421 * Check that all option constraints have been met. This effectively replaces 422 * ->final_check of the older API. 423 */ 424void xtables_options_fcheck(const char *name, unsigned int xflags, 425 const struct xt_option_entry *table) 426{ 427 const struct xt_option_entry *entry, *other; 428 unsigned int i; 429 430 for (entry = table; entry->name != NULL; ++entry) { 431 if (entry->flags & XTOPT_MAND && 432 !(xflags & (1 << entry->id))) 433 xt_params->exit_err(PARAMETER_PROBLEM, 434 "%s: option \"--%s\" must be specified\n", 435 name, entry->name); 436 437 for (i = 0; i < CHAR_BIT * sizeof(entry->id); ++i) { 438 if (entry->id == i) 439 /* 440 * Avoid conflict with self. Multi-use check 441 * was done earlier in xtables_option_parse. 442 */ 443 continue; 444 other = xtables_option_lookup(table, i); 445 if (other == NULL) 446 continue; 447 xtables_option_fcheck2(name, entry, other, xflags); 448 } 449 } 450} 451 452/** 453 * Dispatch arguments to the appropriate final_check function, based upon the 454 * extension's choice of API. 455 */ 456void xtables_option_tfcall(struct xtables_target *t) 457{ 458 if (t->x6_fcheck != NULL) { 459 struct xt_fcheck_call cb; 460 461 cb.ext_name = t->name; 462 cb.data = t->t->data; 463 cb.xflags = t->tflags; 464 t->x6_fcheck(&cb); 465 } else if (t->final_check != NULL) { 466 t->final_check(t->tflags); 467 } 468 if (t->x6_options != NULL) 469 xtables_options_fcheck(t->name, t->tflags, t->x6_options); 470} 471 472/** 473 * Dispatch arguments to the appropriate final_check function, based upon the 474 * extension's choice of API. 475 */ 476void xtables_option_mfcall(struct xtables_match *m) 477{ 478 if (m->x6_fcheck != NULL) { 479 struct xt_fcheck_call cb; 480 481 cb.ext_name = m->name; 482 cb.data = m->m->data; 483 cb.xflags = m->mflags; 484 m->x6_fcheck(&cb); 485 } else if (m->final_check != NULL) { 486 m->final_check(m->mflags); 487 } 488 if (m->x6_options != NULL) 489 xtables_options_fcheck(m->name, m->mflags, m->x6_options); 490} 491 492struct xtables_lmap *xtables_lmap_init(const char *file) 493{ 494 struct xtables_lmap *lmap_head = NULL, *lmap_prev = NULL, *lmap_this; 495 char buf[512]; 496 FILE *fp; 497 char *cur, *nxt; 498 int id; 499 500 fp = fopen(file, "re"); 501 if (fp == NULL) 502 return NULL; 503 504 while (fgets(buf, sizeof(buf), fp) != NULL) { 505 cur = buf; 506 while (isspace(*cur)) 507 ++cur; 508 if (*cur == '#' || *cur == '\n' || *cur == '\0') 509 continue; 510 511 /* iproute2 allows hex and dec format */ 512 errno = 0; 513 id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) == 0 ? 16 : 10); 514 if (nxt == cur || errno != 0) 515 continue; 516 517 /* same boundaries as in iproute2 */ 518 if (id < 0 || id > 255) 519 continue; 520 cur = nxt; 521 522 if (!isspace(*cur)) 523 continue; 524 while (isspace(*cur)) 525 ++cur; 526 if (*cur == '#' || *cur == '\n' || *cur == '\0') 527 continue; 528 nxt = cur; 529 while (*nxt != '\0' && !isspace(*nxt)) 530 ++nxt; 531 if (nxt == cur) 532 continue; 533 *nxt = '\0'; 534 535 /* found valid data */ 536 lmap_this = malloc(sizeof(*lmap_this)); 537 if (lmap_this == NULL) { 538 perror("malloc"); 539 goto out; 540 } 541 lmap_this->id = id; 542 lmap_this->name = strdup(cur); 543 if (lmap_this->name == NULL) { 544 free(lmap_this); 545 goto out; 546 } 547 lmap_this->next = NULL; 548 549 if (lmap_prev != NULL) 550 lmap_prev->next = lmap_this; 551 else 552 lmap_head = lmap_this; 553 lmap_prev = lmap_this; 554 } 555 556 fclose(fp); 557 return lmap_head; 558 out: 559 xtables_lmap_free(lmap_head); 560 return NULL; 561} 562 563void xtables_lmap_free(struct xtables_lmap *head) 564{ 565 struct xtables_lmap *next; 566 567 for (; head != NULL; head = next) { 568 next = head->next; 569 free(head->name); 570 free(head); 571 } 572} 573 574int xtables_lmap_name2id(const struct xtables_lmap *head, const char *name) 575{ 576 for (; head != NULL; head = head->next) 577 if (strcmp(head->name, name) == 0) 578 return head->id; 579 return -1; 580} 581 582const char *xtables_lmap_id2name(const struct xtables_lmap *head, int id) 583{ 584 for (; head != NULL; head = head->next) 585 if (head->id == id) 586 return head->name; 587 return NULL; 588} 589