📄 parse.c
字号:
const char *ptr = str; int negative = 0; u_int32_t val = 0; int tval; int max; if (*ptr == '-') { negative = 1; ++ptr; } /* If base wasn't specified, figure it out from the data. */ if (!base) { if (ptr [0] == '0') { if (ptr [1] == 'x') { base = 16; ptr += 2; } else if (isascii (ptr [1]) && isdigit (ptr [1])) { base = 8; ptr += 1; } else { base = 10; } } else { base = 10; } } do { tval = *ptr++; /* XXX assumes ASCII... */ if (tval >= 'a') tval = tval - 'a' + 10; else if (tval >= 'A') tval = tval - 'A' + 10; else if (tval >= '0') tval -= '0'; else { parse_warn (cfile, "Bogus number: %s.", str); break; } if (tval >= base) { parse_warn (cfile, "Bogus number %s: digit %d not in base %d", str, tval, base); break; } val = val * base + tval; } while (*ptr); if (negative) max = (1 << (size - 1)); else max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); if (val > max) { switch (base) { case 8: parse_warn (cfile, "%s%lo exceeds max (%d) for precision.", negative ? "-" : "", (unsigned long)val, max); break; case 16: parse_warn (cfile, "%s%lx exceeds max (%d) for precision.", negative ? "-" : "", (unsigned long)val, max); break; default: parse_warn (cfile, "%s%lu exceeds max (%d) for precision.", negative ? "-" : "", (unsigned long)val, max); break; } } if (negative) { switch (size) { case 8: *buf = -(unsigned long)val; break; case 16: putShort (buf, -(long)val); break; case 32: putLong (buf, -(long)val); break; default: parse_warn (cfile, "Unexpected integer size: %d\n", size); break; } } else { switch (size) { case 8: *buf = (u_int8_t)val; break; case 16: putUShort (buf, (u_int16_t)val); break; case 32: putULong (buf, val); break; default: parse_warn (cfile, "Unexpected integer size: %d\n", size); break; } }}/* * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER * NUMBER COLON NUMBER COLON NUMBER SEMI | * NUMBER NUMBER SLASH NUMBER SLASH NUMBER * NUMBER COLON NUMBER COLON NUMBER NUMBER SEMI | * NEVER * * Dates are stored in GMT or with a timezone offset; first number is day * of week; next is year/month/day; next is hours:minutes:seconds on a * 24-hour clock, followed by the timezone offset in seconds, which is * optional. */TIME parse_date (cfile) struct parse *cfile;{ struct tm tm; int guess; int tzoff, wday, year, mon, mday, hour, min, sec; const char *val; enum dhcp_token token; static int months [11] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /* Day of week, or "never"... */ token = next_token (&val, (unsigned *)0, cfile); if (token == NEVER) { if (!parse_semi (cfile)) return 0; return MAX_TIME; } if (token != NUMBER) { parse_warn (cfile, "numeric day of week expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } wday = atoi (val); /* Year... */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "numeric year expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until somebody invents a time machine, I think we can safely disregard it. This actually works around a stupid Y2K bug that was present in a very early beta release of dhcpd. */ year = atoi (val); if (year > 1900) year -= 1900; /* Slash seperating year from month... */ token = next_token (&val, (unsigned *)0, cfile); if (token != SLASH) { parse_warn (cfile, "expected slash seperating year from month."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Month... */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "numeric month expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } mon = atoi (val) - 1; /* Slash seperating month from day... */ token = next_token (&val, (unsigned *)0, cfile); if (token != SLASH) { parse_warn (cfile, "expected slash seperating month from day."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Month... */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "numeric day of month expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } mday = atoi (val); /* Hour... */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "numeric hour expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } hour = atoi (val); /* Colon seperating hour from minute... */ token = next_token (&val, (unsigned *)0, cfile); if (token != COLON) { parse_warn (cfile, "expected colon seperating hour from minute."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Minute... */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "numeric minute expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } min = atoi (val); /* Colon seperating minute from second... */ token = next_token (&val, (unsigned *)0, cfile); if (token != COLON) { parse_warn (cfile, "expected colon seperating hour from minute."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Minute... */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "numeric minute expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } sec = atoi (val); token = peek_token (&val, (unsigned *)0, cfile); if (token == NUMBER) { token = next_token (&val, (unsigned *)0, cfile); tzoff = atoi (val); } else tzoff = 0; /* Make sure the date ends in a semicolon... */ if (!parse_semi (cfile)) return 0; /* Guess the time value... */ guess = ((((((365 * (year - 70) + /* Days in years since '70 */ (year - 69) / 4 + /* Leap days since '70 */ (mon /* Days in months this year */ ? months [mon - 1] : 0) + (mon > 1 && /* Leap day this year */ !((year - 72) & 3)) + mday - 1) * 24) + /* Day of month */ hour) * 60) + min) * 60) + sec + tzoff; /* This guess could be wrong because of leap seconds or other weirdness we don't know about that the system does. For now, we're just going to accept the guess, but at some point it might be nice to do a successive approximation here to get an exact value. Even if the error is small, if the server is restarted frequently (and thus the lease database is reread), the error could accumulate into something significant. */ return guess;}/* * option-name :== IDENTIFIER | IDENTIFIER . IDENTIFIER */struct option *parse_option_name (cfile, allocate, known) struct parse *cfile; int allocate; int *known;{ const char *val; enum dhcp_token token; char *uname; struct universe *universe; struct option *option; token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier after option keyword."); if (token != SEMI) skip_to_semi (cfile); return (struct option *)0; } uname = dmalloc (strlen (val) + 1, MDL); if (!uname) log_fatal ("no memory for uname information."); strcpy (uname, val); token = peek_token (&val, (unsigned *)0, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ token = next_token (&val, (unsigned *)0, cfile); /* The next token should be an identifier... */ token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier after '.'"); if (token != SEMI) skip_to_semi (cfile); return (struct option *)0; } /* Look up the option name hash table for the specified uname. */ universe = (struct universe *)0; if (!universe_hash_lookup (&universe, universe_hash, uname, 0, MDL)) { parse_warn (cfile, "no option space named %s.", uname); skip_to_semi (cfile); return (struct option *)0; } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ val = uname; universe = &dhcp_universe; } /* Look up the actual option info... */ option = (struct option *)0; option_hash_lookup (&option, universe -> hash, val, 0, MDL); /* If we didn't get an option structure, it's an undefined option. */ if (option) { if (known) *known = 1; } else { /* If we've been told to allocate, that means that this (might) be an option code definition, so we'll create an option structure just in case. */ if (allocate) { option = new_option (MDL); if (val == uname) option -> name = val; else { char *s; dfree (uname, MDL); s = dmalloc (strlen (val) + 1, MDL); if (!s) log_fatal ("no memory for option %s.%s", universe -> name, val); strcpy (s, val); option -> name = s; } option -> universe = universe; option -> code = 0; return option; } if (val == uname) parse_warn (cfile, "no option named %s", val); else parse_warn (cfile, "no option named %s in space %s", val, uname); skip_to_semi (cfile); return (struct option *)0; } /* Free the initial identifier token. */ dfree (uname, MDL); return option;}/* IDENTIFIER SEMI */void parse_option_space_decl (cfile) struct parse *cfile;{ int token; const char *val; struct universe **ua, *nu; char *s; next_token (&val, (unsigned *)0, cfile); /* Discard the SPACE token, which was checked by the caller. */ token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier."); skip_to_semi (cfile); return; } nu = new_universe (MDL); if (!nu) log_fatal ("No memory for new option space."); /* Set up the server option universe... */ s = dmalloc (strlen (val) + 1, MDL); if (!s) log_fatal ("No memory for new option space name."); strcpy (s, val); nu -> name = s; nu -> lookup_func = lookup_hashed_option; nu -> option_state_dereference = hashed_option_state_dereference; nu -> foreach = hashed_option_space_foreach; nu -> save_func = save_hashed_option; nu -> delete_func = delete_hashed_option; nu -> encapsulate = hashed_option_space_encapsulate; nu -> decode = parse_option_buffer; nu -> length_size = 1; nu -> tag_size = 1; nu -> store_tag = putUChar; nu -> store_length = putUChar; nu -> index = universe_count++; if (nu -> index >= universe_max) { ua = dmalloc (universe_max * 2 * sizeof *ua, MDL); if (!ua) log_fatal ("No memory to expand option space array."); memcpy (ua, universes, universe_max * sizeof *ua); universe_max *= 2; dfree (universes, MDL); universes = ua; } universes [nu -> index] = nu; option_new_hash (&nu -> hash, 1, MDL); if (!nu -> hash) log_fatal ("Can't allocate %s option hash table.", nu -> name); universe_hash_add (universe_hash, nu -> name, 0, nu, MDL); parse_semi (cfile);}/* This is faked up to look good right now. Ideally, this should do a recursive parse and allow arbitrary data structure definitions, but for now it just allows you to specify a single type, an array of single types, a sequence of types, or an array of sequences of types. ocd :== NUMBER EQUALS ocsd SEMI ocsd :== ocsd_type | ocsd_type_sequence | ARRAY OF ocsd_simple_type_sequence ocsd_type_sequence :== LBRACE ocsd_types RBRACE ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE ocsd_types :== ocsd_type | ocsd_types ocsd_type ocsd_type :== ocsd_simple_type | ARRAY OF ocsd_simple_type ocsd_simple_types :== ocsd_simple_type | ocsd_simple_types ocsd_simple_type ocsd_simple_type :== BOOLEAN | INTEGER NUMBER | SIGNED INTEGER NUMBER | UNSIGNED INTEGER NUMBER | IP-ADDRESS | TEXT | STRING | ENCAPSULATE identifier */int parse_option_code_definition (cfile, option) struct parse *cfile; struct option *option;{ const char *val; enum dhcp_token token; unsigned arrayp = 0; int recordp = 0; int no_more_in_record = 0; char tokbuf [128]; unsigned tokix = 0; char type; int code; int is_signed; char *s; int has_encapsulation = 0; /* Parse the option code. */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting option code number."); skip_to_semi (cfile); return 0; } option -> code = atoi (val); token = next_token (&val, (unsigned *)0, cfile); if (token != EQUAL) { parse_warn (cfile, "expecting \"=\""); skip_to_semi (cfile); return 0; } /* See if this is an array. */ token = next_token (&val, (unsigned *)0, cfile);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -