1 /* 2 * rdata.c 3 * 4 * rdata implementation 5 * 6 * a Net::DNS like library for C 7 * 8 * (c) NLnet Labs, 2004-2006 9 * 10 * See the file LICENSE for the license 11 */ 12 13 #include <ldns/config.h> 14 15 #include <ldns/ldns.h> 16 17 /* 18 * Access functions 19 * do this as functions to get type checking 20 */ 21 22 /* read */ 23 size_t 24 ldns_rdf_size(const ldns_rdf *rd) 25 { 26 assert(rd != NULL); 27 return rd->_size; 28 } 29 30 ldns_rdf_type 31 ldns_rdf_get_type(const ldns_rdf *rd) 32 { 33 assert(rd != NULL); 34 return rd->_type; 35 } 36 37 uint8_t * 38 ldns_rdf_data(const ldns_rdf *rd) 39 { 40 assert(rd != NULL); 41 return rd->_data; 42 } 43 44 /* write */ 45 void 46 ldns_rdf_set_size(ldns_rdf *rd, size_t size) 47 { 48 assert(rd != NULL); 49 rd->_size = size; 50 } 51 52 void 53 ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type) 54 { 55 assert(rd != NULL); 56 rd->_type = type; 57 } 58 59 void 60 ldns_rdf_set_data(ldns_rdf *rd, void *data) 61 { 62 /* only copy the pointer */ 63 assert(rd != NULL); 64 rd->_data = data; 65 } 66 67 /* for types that allow it, return 68 * the native/host order type */ 69 uint8_t 70 ldns_rdf2native_int8(const ldns_rdf *rd) 71 { 72 uint8_t data; 73 74 /* only allow 8 bit rdfs */ 75 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) { 76 return 0; 77 } 78 79 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 80 return data; 81 } 82 83 uint16_t 84 ldns_rdf2native_int16(const ldns_rdf *rd) 85 { 86 uint16_t data; 87 88 /* only allow 16 bit rdfs */ 89 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) { 90 return 0; 91 } 92 93 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 94 return ntohs(data); 95 } 96 97 uint32_t 98 ldns_rdf2native_int32(const ldns_rdf *rd) 99 { 100 uint32_t data; 101 102 /* only allow 32 bit rdfs */ 103 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) { 104 return 0; 105 } 106 107 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 108 return ntohl(data); 109 } 110 111 time_t 112 ldns_rdf2native_time_t(const ldns_rdf *rd) 113 { 114 uint32_t data; 115 116 /* only allow 32 bit rdfs */ 117 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD || 118 ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TIME) { 119 return 0; 120 } 121 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 122 return (time_t)ntohl(data); 123 } 124 125 ldns_rdf * 126 ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value) 127 { 128 return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value); 129 } 130 131 ldns_rdf * 132 ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value) 133 { 134 uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1); 135 ldns_rdf* rdf; 136 if (!rdf_data) { 137 return NULL; 138 } 139 ldns_write_uint16(rdf_data, value); 140 rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data); 141 if(!rdf) 142 LDNS_FREE(rdf_data); 143 return rdf; 144 } 145 146 ldns_rdf * 147 ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value) 148 { 149 uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1); 150 ldns_rdf* rdf; 151 if (!rdf_data) { 152 return NULL; 153 } 154 ldns_write_uint32(rdf_data, value); 155 rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data); 156 if(!rdf) 157 LDNS_FREE(rdf_data); 158 return rdf; 159 } 160 161 ldns_rdf * 162 ldns_native2rdf_int16_data(size_t size, uint8_t *data) 163 { 164 uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2); 165 ldns_rdf* rdf; 166 if (!rdf_data) { 167 return NULL; 168 } 169 ldns_write_uint16(rdf_data, size); 170 memcpy(rdf_data + 2, data, size); 171 rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data); 172 if(!rdf) 173 LDNS_FREE(rdf_data); 174 return rdf; 175 } 176 177 /* note: data must be allocated memory */ 178 ldns_rdf * 179 ldns_rdf_new(ldns_rdf_type type, size_t size, void *data) 180 { 181 ldns_rdf *rd; 182 rd = LDNS_MALLOC(ldns_rdf); 183 if (!rd) { 184 return NULL; 185 } 186 ldns_rdf_set_size(rd, size); 187 ldns_rdf_set_type(rd, type); 188 ldns_rdf_set_data(rd, data); 189 return rd; 190 } 191 192 ldns_rdf * 193 ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data) 194 { 195 ldns_rdf *rdf; 196 197 /* if the size is too big, fail */ 198 if (size > LDNS_MAX_RDFLEN) { 199 return NULL; 200 } 201 202 /* allocate space */ 203 rdf = LDNS_MALLOC(ldns_rdf); 204 if (!rdf) { 205 return NULL; 206 } 207 rdf->_data = LDNS_XMALLOC(uint8_t, size); 208 if (!rdf->_data) { 209 LDNS_FREE(rdf); 210 return NULL; 211 } 212 213 /* set the values */ 214 ldns_rdf_set_type(rdf, type); 215 ldns_rdf_set_size(rdf, size); 216 memcpy(rdf->_data, data, size); 217 218 return rdf; 219 } 220 221 ldns_rdf * 222 ldns_rdf_clone(const ldns_rdf *rd) 223 { 224 assert(rd != NULL); 225 return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd), 226 ldns_rdf_size(rd), ldns_rdf_data(rd))); 227 } 228 229 void 230 ldns_rdf_deep_free(ldns_rdf *rd) 231 { 232 if (rd) { 233 if (rd->_data) { 234 LDNS_FREE(rd->_data); 235 } 236 LDNS_FREE(rd); 237 } 238 } 239 240 void 241 ldns_rdf_free(ldns_rdf *rd) 242 { 243 if (rd) { 244 LDNS_FREE(rd); 245 } 246 } 247 248 ldns_rdf * 249 ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str) 250 { 251 ldns_rdf *rdf = NULL; 252 ldns_status status; 253 254 switch (type) { 255 case LDNS_RDF_TYPE_DNAME: 256 status = ldns_str2rdf_dname(&rdf, str); 257 break; 258 case LDNS_RDF_TYPE_INT8: 259 status = ldns_str2rdf_int8(&rdf, str); 260 break; 261 case LDNS_RDF_TYPE_INT16: 262 status = ldns_str2rdf_int16(&rdf, str); 263 break; 264 case LDNS_RDF_TYPE_INT32: 265 status = ldns_str2rdf_int32(&rdf, str); 266 break; 267 case LDNS_RDF_TYPE_A: 268 status = ldns_str2rdf_a(&rdf, str); 269 break; 270 case LDNS_RDF_TYPE_AAAA: 271 status = ldns_str2rdf_aaaa(&rdf, str); 272 break; 273 case LDNS_RDF_TYPE_STR: 274 status = ldns_str2rdf_str(&rdf, str); 275 break; 276 case LDNS_RDF_TYPE_APL: 277 status = ldns_str2rdf_apl(&rdf, str); 278 break; 279 case LDNS_RDF_TYPE_B64: 280 status = ldns_str2rdf_b64(&rdf, str); 281 break; 282 case LDNS_RDF_TYPE_B32_EXT: 283 status = ldns_str2rdf_b32_ext(&rdf, str); 284 break; 285 case LDNS_RDF_TYPE_HEX: 286 status = ldns_str2rdf_hex(&rdf, str); 287 break; 288 case LDNS_RDF_TYPE_NSEC: 289 status = ldns_str2rdf_nsec(&rdf, str); 290 break; 291 case LDNS_RDF_TYPE_TYPE: 292 status = ldns_str2rdf_type(&rdf, str); 293 break; 294 case LDNS_RDF_TYPE_CLASS: 295 status = ldns_str2rdf_class(&rdf, str); 296 break; 297 case LDNS_RDF_TYPE_CERT_ALG: 298 status = ldns_str2rdf_cert_alg(&rdf, str); 299 break; 300 case LDNS_RDF_TYPE_ALG: 301 status = ldns_str2rdf_alg(&rdf, str); 302 break; 303 case LDNS_RDF_TYPE_UNKNOWN: 304 status = ldns_str2rdf_unknown(&rdf, str); 305 break; 306 case LDNS_RDF_TYPE_TIME: 307 status = ldns_str2rdf_time(&rdf, str); 308 break; 309 case LDNS_RDF_TYPE_PERIOD: 310 status = ldns_str2rdf_period(&rdf, str); 311 break; 312 case LDNS_RDF_TYPE_HIP: 313 status = ldns_str2rdf_hip(&rdf, str); 314 break; 315 case LDNS_RDF_TYPE_SERVICE: 316 status = ldns_str2rdf_service(&rdf, str); 317 break; 318 case LDNS_RDF_TYPE_LOC: 319 status = ldns_str2rdf_loc(&rdf, str); 320 break; 321 case LDNS_RDF_TYPE_WKS: 322 status = ldns_str2rdf_wks(&rdf, str); 323 break; 324 case LDNS_RDF_TYPE_NSAP: 325 status = ldns_str2rdf_nsap(&rdf, str); 326 break; 327 case LDNS_RDF_TYPE_ATMA: 328 status = ldns_str2rdf_atma(&rdf, str); 329 break; 330 case LDNS_RDF_TYPE_IPSECKEY: 331 status = ldns_str2rdf_ipseckey(&rdf, str); 332 break; 333 case LDNS_RDF_TYPE_NSEC3_SALT: 334 status = ldns_str2rdf_nsec3_salt(&rdf, str); 335 break; 336 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 337 status = ldns_str2rdf_b32_ext(&rdf, str); 338 break; 339 case LDNS_RDF_TYPE_ILNP64: 340 status = ldns_str2rdf_ilnp64(&rdf, str); 341 break; 342 case LDNS_RDF_TYPE_EUI48: 343 status = ldns_str2rdf_eui48(&rdf, str); 344 break; 345 case LDNS_RDF_TYPE_EUI64: 346 status = ldns_str2rdf_eui64(&rdf, str); 347 break; 348 case LDNS_RDF_TYPE_TAG: 349 status = ldns_str2rdf_tag(&rdf, str); 350 break; 351 case LDNS_RDF_TYPE_LONG_STR: 352 status = ldns_str2rdf_long_str(&rdf, str); 353 break; 354 case LDNS_RDF_TYPE_CERTIFICATE_USAGE: 355 status = ldns_str2rdf_certificate_usage(&rdf, str); 356 break; 357 case LDNS_RDF_TYPE_SELECTOR: 358 status = ldns_str2rdf_selector(&rdf, str); 359 break; 360 case LDNS_RDF_TYPE_MATCHING_TYPE: 361 status = ldns_str2rdf_matching_type(&rdf, str); 362 break; 363 case LDNS_RDF_TYPE_AMTRELAY: 364 status = ldns_str2rdf_amtrelay(&rdf, str); 365 break; 366 case LDNS_RDF_TYPE_SVCPARAMS: 367 status = ldns_str2rdf_svcparams(&rdf, str); 368 break; 369 case LDNS_RDF_TYPE_NONE: 370 default: 371 /* default default ??? */ 372 status = LDNS_STATUS_ERR; 373 break; 374 } 375 if (LDNS_STATUS_OK == status) { 376 ldns_rdf_set_type(rdf, type); 377 return rdf; 378 } 379 if (rdf) { 380 LDNS_FREE(rdf); 381 } 382 return NULL; 383 } 384 385 ldns_status 386 ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp) 387 { 388 return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL); 389 } 390 391 ldns_status 392 ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr) 393 { 394 char *line; 395 ldns_rdf *r; 396 ssize_t t; 397 398 line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); 399 if (!line) { 400 return LDNS_STATUS_MEM_ERR; 401 } 402 403 /* read an entire line in from the file */ 404 if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) { 405 LDNS_FREE(line); 406 return LDNS_STATUS_SYNTAX_RDATA_ERR; 407 } 408 r = ldns_rdf_new_frm_str(type, (const char*) line); 409 LDNS_FREE(line); 410 if (rdf) { 411 *rdf = r; 412 return LDNS_STATUS_OK; 413 } else { 414 return LDNS_STATUS_NULL; 415 } 416 } 417 418 ldns_rdf * 419 ldns_rdf_address_reverse(const ldns_rdf *rd) 420 { 421 uint8_t buf_4[LDNS_IP4ADDRLEN]; 422 uint8_t buf_6[LDNS_IP6ADDRLEN * 2]; 423 ldns_rdf *rev; 424 ldns_rdf *in_addr; 425 ldns_rdf *ret_dname; 426 uint8_t octet; 427 uint8_t nnibble; 428 uint8_t nibble; 429 uint8_t i, j; 430 431 char *char_dname; 432 int nbit; 433 434 if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A && 435 ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) { 436 return NULL; 437 } 438 439 in_addr = NULL; 440 ret_dname = NULL; 441 442 switch(ldns_rdf_get_type(rd)) { 443 case LDNS_RDF_TYPE_A: 444 /* the length of the buffer is 4 */ 445 buf_4[3] = ldns_rdf_data(rd)[0]; 446 buf_4[2] = ldns_rdf_data(rd)[1]; 447 buf_4[1] = ldns_rdf_data(rd)[2]; 448 buf_4[0] = ldns_rdf_data(rd)[3]; 449 in_addr = ldns_dname_new_frm_str("in-addr.arpa."); 450 if (!in_addr) { 451 return NULL; 452 } 453 /* make a new rdf and convert that back */ 454 rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A, 455 LDNS_IP4ADDRLEN, (void*)&buf_4); 456 if (!rev) { 457 LDNS_FREE(in_addr); 458 return NULL; 459 } 460 461 /* convert rev to a string */ 462 char_dname = ldns_rdf2str(rev); 463 if (!char_dname) { 464 LDNS_FREE(in_addr); 465 ldns_rdf_deep_free(rev); 466 return NULL; 467 } 468 /* transform back to rdf with type dname */ 469 ret_dname = ldns_dname_new_frm_str(char_dname); 470 if (!ret_dname) { 471 LDNS_FREE(in_addr); 472 ldns_rdf_deep_free(rev); 473 LDNS_FREE(char_dname); 474 return NULL; 475 } 476 /* not needed anymore */ 477 ldns_rdf_deep_free(rev); 478 LDNS_FREE(char_dname); 479 break; 480 case LDNS_RDF_TYPE_AAAA: 481 /* some foo magic to reverse the nibbles ... */ 482 483 for (nbit = 127; nbit >= 0; nbit = nbit - 4) { 484 /* calculate octet (8 bit) */ 485 octet = ( ((unsigned int) nbit) & 0x78) >> 3; 486 /* calculate nibble */ 487 nnibble = ( ((unsigned int) nbit) & 0x04) >> 2; 488 /* extract nibble */ 489 nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 - 490 nnibble)) ) ) >> ( 4 * (1 - 491 nnibble)); 492 493 buf_6[(LDNS_IP6ADDRLEN * 2 - 1) - 494 (octet * 2 + nnibble)] = 495 (uint8_t)ldns_int_to_hexdigit((int)nibble); 496 } 497 498 char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4)); 499 if (!char_dname) { 500 return NULL; 501 } 502 char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */ 503 504 /* walk the string and add . 's */ 505 for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) { 506 char_dname[j] = (char)buf_6[i]; 507 if (i != LDNS_IP6ADDRLEN * 2 - 1) { 508 char_dname[j + 1] = '.'; 509 } 510 } 511 in_addr = ldns_dname_new_frm_str("ip6.arpa."); 512 if (!in_addr) { 513 LDNS_FREE(char_dname); 514 return NULL; 515 } 516 517 /* convert rev to a string */ 518 ret_dname = ldns_dname_new_frm_str(char_dname); 519 LDNS_FREE(char_dname); 520 if (!ret_dname) { 521 ldns_rdf_deep_free(in_addr); 522 return NULL; 523 } 524 break; 525 default: 526 break; 527 } 528 /* add the suffix */ 529 rev = ldns_dname_cat_clone(ret_dname, in_addr); 530 531 ldns_rdf_deep_free(ret_dname); 532 ldns_rdf_deep_free(in_addr); 533 return rev; 534 } 535 536 ldns_status 537 ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, 538 uint8_t *hit_size, uint8_t** hit, 539 uint16_t *pk_size, uint8_t** pk) 540 { 541 uint8_t *data; 542 size_t rdf_size; 543 544 if (! rdf || ! alg || ! hit || ! hit_size || ! pk || ! pk_size) { 545 return LDNS_STATUS_INVALID_POINTER; 546 } else if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_HIP) { 547 return LDNS_STATUS_INVALID_RDF_TYPE; 548 } else if ((rdf_size = ldns_rdf_size(rdf)) < 6) { 549 return LDNS_STATUS_WIRE_RDATA_ERR; 550 } 551 data = ldns_rdf_data(rdf); 552 *hit_size = data[0]; 553 *alg = data[1]; 554 *pk_size = ldns_read_uint16(data + 2); 555 *hit = data + 4; 556 *pk = data + 4 + *hit_size; 557 if (*hit_size == 0 || *pk_size == 0 || 558 rdf_size < (size_t) *hit_size + *pk_size + 4) { 559 return LDNS_STATUS_WIRE_RDATA_ERR; 560 } 561 return LDNS_STATUS_OK; 562 } 563 564 ldns_status 565 ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, 566 uint8_t hit_size, uint8_t *hit, 567 uint16_t pk_size, uint8_t *pk) 568 { 569 uint8_t *data; 570 571 if (! rdf) { 572 return LDNS_STATUS_INVALID_POINTER; 573 } 574 if (4 + hit_size + pk_size > LDNS_MAX_RDFLEN) { 575 return LDNS_STATUS_RDATA_OVERFLOW; 576 } 577 data = LDNS_XMALLOC(uint8_t, 4 + hit_size + pk_size); 578 if (data == NULL) { 579 return LDNS_STATUS_MEM_ERR; 580 } 581 data[0] = hit_size; 582 data[1] = alg; 583 ldns_write_uint16(data + 2, pk_size); 584 memcpy(data + 4, hit, hit_size); 585 memcpy(data + 4 + hit_size, pk, pk_size); 586 *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HIP, 4 + hit_size + pk_size, data); 587 if (! *rdf) { 588 LDNS_FREE(data); 589 return LDNS_STATUS_MEM_ERR; 590 } 591 return LDNS_STATUS_OK; 592 } 593 594 ldns_status 595 ldns_octet(char *word, size_t *length) 596 { 597 char *s; 598 char *p; 599 *length = 0; 600 601 for (s = p = word; *s != '\0'; s++,p++) { 602 switch (*s) { 603 case '.': 604 if (s[1] == '.') { 605 return LDNS_STATUS_EMPTY_LABEL; 606 } 607 *p = *s; 608 (*length)++; 609 break; 610 case '\\': 611 if ('0' <= s[1] && s[1] <= '9' && 612 '0' <= s[2] && s[2] <= '9' && 613 '0' <= s[3] && s[3] <= '9') { 614 /* \DDD seen */ 615 int val = ((s[1] - '0') * 100 + 616 (s[2] - '0') * 10 + (s[3] - '0')); 617 618 if (0 <= val && val <= 255) { 619 /* this also handles \0 */ 620 s += 3; 621 *p = val; 622 (*length)++; 623 } else { 624 return LDNS_STATUS_DDD_OVERFLOW; 625 } 626 } else { 627 /* an escaped character, like \<space> ? 628 * remove the '\' keep the rest */ 629 *p = *++s; 630 (*length)++; 631 } 632 break; 633 case '\"': 634 /* non quoted " Is either first or the last character in 635 * the string */ 636 637 *p = *++s; /* skip it */ 638 (*length)++; 639 /* I'm not sure if this is needed in libdns... MG */ 640 if ( *s == '\0' ) { 641 /* ok, it was the last one */ 642 *p = '\0'; 643 return LDNS_STATUS_OK; 644 } 645 break; 646 default: 647 *p = *s; 648 (*length)++; 649 break; 650 } 651 } 652 *p = '\0'; 653 return LDNS_STATUS_OK; 654 } 655 656 int 657 ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2) 658 { 659 uint16_t i1, i2, i; 660 uint8_t *d1, *d2; 661 662 /* only when both are not NULL we can say anything about them */ 663 if (!rd1 && !rd2) { 664 return 0; 665 } 666 if (!rd1 || !rd2) { 667 return -1; 668 } 669 i1 = ldns_rdf_size(rd1); 670 i2 = ldns_rdf_size(rd2); 671 672 if (i1 < i2) { 673 return -1; 674 } else if (i1 > i2) { 675 return +1; 676 } else { 677 d1 = (uint8_t*)ldns_rdf_data(rd1); 678 d2 = (uint8_t*)ldns_rdf_data(rd2); 679 for(i = 0; i < i1; i++) { 680 if (d1[i] < d2[i]) { 681 return -1; 682 } else if (d1[i] > d2[i]) { 683 return +1; 684 } 685 } 686 } 687 return 0; 688 } 689 690 uint32_t 691 ldns_str2period(const char *nptr, const char **endptr) 692 { 693 int sign = 0; 694 uint32_t i = 0; 695 uint32_t seconds = 0; 696 697 for(*endptr = nptr; **endptr; (*endptr)++) { 698 switch (**endptr) { 699 case ' ': 700 case '\t': 701 break; 702 case '-': 703 if(sign == 0) { 704 sign = -1; 705 } else { 706 return seconds; 707 } 708 break; 709 case '+': 710 if(sign == 0) { 711 sign = 1; 712 } else { 713 return seconds; 714 } 715 break; 716 case 's': 717 case 'S': 718 seconds += i; 719 i = 0; 720 break; 721 case 'm': 722 case 'M': 723 seconds += i * 60; 724 i = 0; 725 break; 726 case 'h': 727 case 'H': 728 seconds += i * 60 * 60; 729 i = 0; 730 break; 731 case 'd': 732 case 'D': 733 seconds += i * 60 * 60 * 24; 734 i = 0; 735 break; 736 case 'w': 737 case 'W': 738 seconds += i * 60 * 60 * 24 * 7; 739 i = 0; 740 break; 741 case '0': 742 case '1': 743 case '2': 744 case '3': 745 case '4': 746 case '5': 747 case '6': 748 case '7': 749 case '8': 750 case '9': 751 i *= 10; 752 i += (**endptr - '0'); 753 break; 754 default: 755 seconds += i; 756 /* disregard signedness */ 757 return seconds; 758 } 759 } 760 seconds += i; 761 /* disregard signedness */ 762 return seconds; 763 } 764