1 /* 2 * lib/utils.c Utility Functions 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup core 14 * @defgroup utils Utilities 15 * @{ 16 */ 17 18 #include <netlink-local.h> 19 #include <netlink/netlink.h> 20 #include <netlink/utils.h> 21 #include <linux/socket.h> 22 23 /** 24 * Debug level 25 */ 26 int nl_debug = 0; 27 28 struct nl_dump_params nl_debug_dp = { 29 .dp_type = NL_DUMP_DETAILS, 30 }; 31 32 static void __init nl_debug_init(void) 33 { 34 char *nldbg, *end; 35 36 if ((nldbg = getenv("NLDBG"))) { 37 long level = strtol(nldbg, &end, 0); 38 if (nldbg != end) 39 nl_debug = level; 40 } 41 42 nl_debug_dp.dp_fd = stderr; 43 } 44 45 int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) 46 { 47 FILE *fd; 48 char buf[128]; 49 50 fd = fopen(path, "r"); 51 if (fd == NULL) 52 return -nl_syserr2nlerr(errno); 53 54 while (fgets(buf, sizeof(buf), fd)) { 55 int goodlen, err; 56 long num; 57 char *end; 58 59 if (*buf == '#' || *buf == '\n' || *buf == '\r') 60 continue; 61 62 num = strtol(buf, &end, 0); 63 if (end == buf) 64 return -NLE_INVAL; 65 66 if (num == LONG_MIN || num == LONG_MAX) 67 return -NLE_RANGE; 68 69 while (*end == ' ' || *end == '\t') 70 end++; 71 72 goodlen = strcspn(end, "#\r\n\t "); 73 if (goodlen == 0) 74 return -NLE_INVAL; 75 76 end[goodlen] = '\0'; 77 78 err = cb(num, end); 79 if (err < 0) 80 return err; 81 } 82 83 fclose(fd); 84 85 return 0; 86 } 87 88 /** 89 * @name Unit Pretty-Printing 90 * @{ 91 */ 92 93 /** 94 * Cancel down a byte counter 95 * @arg l byte counter 96 * @arg unit destination unit pointer 97 * 98 * Cancels down a byte counter until it reaches a reasonable 99 * unit. The chosen unit is assigned to \a unit. 100 * 101 * @return The cancelled down byte counter in the new unit. 102 */ 103 double nl_cancel_down_bytes(unsigned long long l, char **unit) 104 { 105 if (l >= 1099511627776LL) { 106 *unit = "TiB"; 107 return ((double) l) / 1099511627776LL; 108 } else if (l >= 1073741824) { 109 *unit = "GiB"; 110 return ((double) l) / 1073741824; 111 } else if (l >= 1048576) { 112 *unit = "MiB"; 113 return ((double) l) / 1048576; 114 } else if (l >= 1024) { 115 *unit = "KiB"; 116 return ((double) l) / 1024; 117 } else { 118 *unit = "B"; 119 return (double) l; 120 } 121 } 122 123 /** 124 * Cancel down a bit counter 125 * @arg l bit counter 126 * @arg unit destination unit pointer 127 * 128 * Cancels downa bit counter until it reaches a reasonable 129 * unit. The chosen unit is assigned to \a unit. 130 * 131 * @return The cancelled down bit counter in the new unit. 132 */ 133 double nl_cancel_down_bits(unsigned long long l, char **unit) 134 { 135 if (l >= 1099511627776ULL) { 136 *unit = "Tbit"; 137 return ((double) l) / 1099511627776ULL; 138 } else if (l >= 1073741824) { 139 *unit = "Gbit"; 140 return ((double) l) / 1073741824; 141 } else if (l >= 1048576) { 142 *unit = "Mbit"; 143 return ((double) l) / 1048576; 144 } else if (l >= 1024) { 145 *unit = "Kbit"; 146 return ((double) l) / 1024; 147 } else { 148 *unit = "bit"; 149 return (double) l; 150 } 151 152 } 153 154 /** 155 * Cancel down a micro second value 156 * @arg l micro seconds 157 * @arg unit destination unit pointer 158 * 159 * Cancels down a microsecond counter until it reaches a 160 * reasonable unit. The chosen unit is assigned to \a unit. 161 * 162 * @return The cancelled down microsecond in the new unit 163 */ 164 double nl_cancel_down_us(uint32_t l, char **unit) 165 { 166 if (l >= 1000000) { 167 *unit = "s"; 168 return ((double) l) / 1000000; 169 } else if (l >= 1000) { 170 *unit = "ms"; 171 return ((double) l) / 1000; 172 } else { 173 *unit = "us"; 174 return (double) l; 175 } 176 } 177 178 /** @} */ 179 180 /** 181 * @name Generic Unit Translations 182 * @{ 183 */ 184 185 /** 186 * Convert a character string to a size 187 * @arg str size encoded as character string 188 * 189 * Converts the specified size as character to the corresponding 190 * number of bytes. 191 * 192 * Supported formats are: 193 * - b,kb/k,m/mb,gb/g for bytes 194 * - bit,kbit/mbit/gbit 195 * 196 * @return The number of bytes or -1 if the string is unparseable 197 */ 198 long nl_size2int(const char *str) 199 { 200 char *p; 201 long l = strtol(str, &p, 0); 202 if (p == str) 203 return -NLE_INVAL; 204 205 if (*p) { 206 if (!strcasecmp(p, "kb") || !strcasecmp(p, "k")) 207 l *= 1024; 208 else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g")) 209 l *= 1024*1024*1024; 210 else if (!strcasecmp(p, "gbit")) 211 l *= 1024*1024*1024/8; 212 else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m")) 213 l *= 1024*1024; 214 else if (!strcasecmp(p, "mbit")) 215 l *= 1024*1024/8; 216 else if (!strcasecmp(p, "kbit")) 217 l *= 1024/8; 218 else if (!strcasecmp(p, "bit")) 219 l /= 8; 220 else if (strcasecmp(p, "b") != 0) 221 return -NLE_INVAL; 222 } 223 224 return l; 225 } 226 227 /** 228 * Convert a character string to a probability 229 * @arg str probability encoded as character string 230 * 231 * Converts the specified probability as character to the 232 * corresponding probability number. 233 * 234 * Supported formats are: 235 * - 0.0-1.0 236 * - 0%-100% 237 * 238 * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX 239 */ 240 long nl_prob2int(const char *str) 241 { 242 char *p; 243 double d = strtod(str, &p); 244 245 if (p == str) 246 return -NLE_INVAL; 247 248 if (d > 1.0) 249 d /= 100.0f; 250 251 if (d > 1.0f || d < 0.0f) 252 return -NLE_RANGE; 253 254 if (*p && strcmp(p, "%") != 0) 255 return -NLE_INVAL; 256 257 return rint(d * NL_PROB_MAX); 258 } 259 260 /** @} */ 261 262 /** 263 * @name Time Translations 264 * @{ 265 */ 266 267 #ifdef USER_HZ 268 static uint32_t user_hz = USER_HZ; 269 #else 270 static uint32_t user_hz = 100; 271 #endif 272 273 static double ticks_per_usec = 1.0f; 274 275 /* Retrieves the configured HZ and ticks/us value in the kernel. 276 * The value is cached. Supported ways of getting it: 277 * 278 * 1) environment variable 279 * 2) /proc/net/psched and sysconf 280 * 281 * Supports the environment variables: 282 * PROC_NET_PSCHED - may point to psched file in /proc 283 * PROC_ROOT - may point to /proc fs */ 284 static void __init get_psched_settings(void) 285 { 286 char name[FILENAME_MAX]; 287 FILE *fd; 288 int got_hz = 0; 289 290 if (getenv("HZ")) { 291 long hz = strtol(getenv("HZ"), NULL, 0); 292 293 if (LONG_MIN != hz && LONG_MAX != hz) { 294 user_hz = hz; 295 got_hz = 1; 296 } 297 } 298 299 if (!got_hz) 300 user_hz = sysconf(_SC_CLK_TCK); 301 302 if (getenv("TICKS_PER_USEC")) { 303 double t = strtod(getenv("TICKS_PER_USEC"), NULL); 304 ticks_per_usec = t; 305 } 306 else { 307 if (getenv("PROC_NET_PSCHED")) 308 snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED")); 309 else if (getenv("PROC_ROOT")) 310 snprintf(name, sizeof(name), "%s/net/psched", 311 getenv("PROC_ROOT")); 312 else 313 strncpy(name, "/proc/net/psched", sizeof(name) - 1); 314 315 if ((fd = fopen(name, "r"))) { 316 uint32_t tick, us; 317 /* the file contains 4 hexadecimals, but we just use 318 the first two of them */ 319 fscanf(fd, "%08x %08x", &tick, &us); 320 ticks_per_usec = (double)tick/(double)us; 321 fclose(fd); 322 } 323 } 324 } 325 326 327 /** 328 * Return the value of HZ 329 */ 330 int nl_get_hz(void) 331 { 332 return user_hz; 333 } 334 335 336 /** 337 * Convert micro seconds to ticks 338 * @arg us micro seconds 339 * @return number of ticks 340 */ 341 uint32_t nl_us2ticks(uint32_t us) 342 { 343 return us * ticks_per_usec; 344 } 345 346 347 /** 348 * Convert ticks to micro seconds 349 * @arg ticks number of ticks 350 * @return microseconds 351 */ 352 uint32_t nl_ticks2us(uint32_t ticks) 353 { 354 return ticks / ticks_per_usec; 355 } 356 357 int nl_str2msec(const char *str, uint64_t *result) 358 { 359 uint64_t total = 0, l; 360 int plen; 361 char *p; 362 363 do { 364 l = strtoul(str, &p, 0); 365 if (p == str) 366 return -NLE_INVAL; 367 else if (*p) { 368 plen = strcspn(p, " \t"); 369 370 if (!plen) 371 total += l; 372 else if (!strncasecmp(p, "sec", plen)) 373 total += (l * 1000); 374 else if (!strncasecmp(p, "min", plen)) 375 total += (l * 1000*60); 376 else if (!strncasecmp(p, "hour", plen)) 377 total += (l * 1000*60*60); 378 else if (!strncasecmp(p, "day", plen)) 379 total += (l * 1000*60*60*24); 380 else 381 return -NLE_INVAL; 382 383 str = p + plen; 384 } else 385 total += l; 386 } while (*str && *p); 387 388 *result = total; 389 390 return 0; 391 } 392 393 /** 394 * Convert milliseconds to a character string 395 * @arg msec number of milliseconds 396 * @arg buf destination buffer 397 * @arg len buffer length 398 * 399 * Converts milliseconds to a character string split up in days, hours, 400 * minutes, seconds, and milliseconds and stores it in the specified 401 * destination buffer. 402 * 403 * @return The destination buffer. 404 */ 405 char * nl_msec2str(uint64_t msec, char *buf, size_t len) 406 { 407 int i, split[5]; 408 char *units[] = {"d", "h", "m", "s", "msec"}; 409 410 #define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit 411 _SPLIT(0, 86400000); /* days */ 412 _SPLIT(1, 3600000); /* hours */ 413 _SPLIT(2, 60000); /* minutes */ 414 _SPLIT(3, 1000); /* seconds */ 415 #undef _SPLIT 416 split[4] = msec; 417 418 memset(buf, 0, len); 419 420 for (i = 0; i < ARRAY_SIZE(split); i++) { 421 if (split[i] > 0) { 422 char t[64]; 423 snprintf(t, sizeof(t), "%s%d%s", 424 strlen(buf) ? " " : "", split[i], units[i]); 425 strncat(buf, t, len - strlen(buf) - 1); 426 } 427 } 428 429 return buf; 430 } 431 432 /** @} */ 433 434 /** 435 * @name Netlink Family Translations 436 * @{ 437 */ 438 439 static struct trans_tbl nlfamilies[] = { 440 __ADD(NETLINK_ROUTE,route) 441 __ADD(NETLINK_USERSOCK,usersock) 442 __ADD(NETLINK_FIREWALL,firewall) 443 __ADD(NETLINK_INET_DIAG,inetdiag) 444 __ADD(NETLINK_NFLOG,nflog) 445 __ADD(NETLINK_XFRM,xfrm) 446 __ADD(NETLINK_SELINUX,selinux) 447 __ADD(NETLINK_ISCSI,iscsi) 448 __ADD(NETLINK_AUDIT,audit) 449 __ADD(NETLINK_FIB_LOOKUP,fib_lookup) 450 __ADD(NETLINK_CONNECTOR,connector) 451 __ADD(NETLINK_NETFILTER,netfilter) 452 __ADD(NETLINK_IP6_FW,ip6_fw) 453 __ADD(NETLINK_DNRTMSG,dnrtmsg) 454 __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent) 455 __ADD(NETLINK_GENERIC,generic) 456 __ADD(NETLINK_SCSITRANSPORT,scsitransport) 457 __ADD(NETLINK_ECRYPTFS,ecryptfs) 458 }; 459 460 char * nl_nlfamily2str(int family, char *buf, size_t size) 461 { 462 return __type2str(family, buf, size, nlfamilies, 463 ARRAY_SIZE(nlfamilies)); 464 } 465 466 int nl_str2nlfamily(const char *name) 467 { 468 return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies)); 469 } 470 471 /** 472 * @} 473 */ 474 475 /** 476 * @name Link Layer Protocol Translations 477 * @{ 478 */ 479 480 static struct trans_tbl llprotos[] = { 481 {0, "generic"}, 482 __ADD(ARPHRD_ETHER,ether) 483 __ADD(ARPHRD_EETHER,eether) 484 __ADD(ARPHRD_AX25,ax25) 485 __ADD(ARPHRD_PRONET,pronet) 486 __ADD(ARPHRD_CHAOS,chaos) 487 __ADD(ARPHRD_IEEE802,ieee802) 488 __ADD(ARPHRD_ARCNET,arcnet) 489 __ADD(ARPHRD_APPLETLK,atalk) 490 __ADD(ARPHRD_DLCI,dlci) 491 __ADD(ARPHRD_ATM,atm) 492 __ADD(ARPHRD_METRICOM,metricom) 493 __ADD(ARPHRD_IEEE1394,ieee1394) 494 #ifdef ARPHRD_EUI64 495 __ADD(ARPHRD_EUI64,eui64) 496 #endif 497 __ADD(ARPHRD_INFINIBAND,infiniband) 498 __ADD(ARPHRD_SLIP,slip) 499 __ADD(ARPHRD_CSLIP,cslip) 500 __ADD(ARPHRD_SLIP6,slip6) 501 __ADD(ARPHRD_CSLIP6,cslip6) 502 __ADD(ARPHRD_RSRVD,rsrvd) 503 __ADD(ARPHRD_ADAPT,adapt) 504 __ADD(ARPHRD_ROSE,rose) 505 __ADD(ARPHRD_X25,x25) 506 #ifdef ARPHRD_HWX25 507 __ADD(ARPHRD_HWX25,hwx25) 508 #endif 509 __ADD(ARPHRD_PPP,ppp) 510 __ADD(ARPHRD_HDLC,hdlc) 511 __ADD(ARPHRD_LAPB,lapb) 512 __ADD(ARPHRD_DDCMP,ddcmp) 513 __ADD(ARPHRD_RAWHDLC,rawhdlc) 514 __ADD(ARPHRD_TUNNEL,ipip) 515 __ADD(ARPHRD_TUNNEL6,tunnel6) 516 __ADD(ARPHRD_FRAD,frad) 517 __ADD(ARPHRD_SKIP,skip) 518 __ADD(ARPHRD_LOOPBACK,loopback) 519 __ADD(ARPHRD_LOCALTLK,localtlk) 520 __ADD(ARPHRD_FDDI,fddi) 521 __ADD(ARPHRD_BIF,bif) 522 __ADD(ARPHRD_SIT,sit) 523 __ADD(ARPHRD_IPDDP,ip/ddp) 524 __ADD(ARPHRD_IPGRE,gre) 525 __ADD(ARPHRD_PIMREG,pimreg) 526 __ADD(ARPHRD_HIPPI,hippi) 527 __ADD(ARPHRD_ASH,ash) 528 __ADD(ARPHRD_ECONET,econet) 529 __ADD(ARPHRD_IRDA,irda) 530 __ADD(ARPHRD_FCPP,fcpp) 531 __ADD(ARPHRD_FCAL,fcal) 532 __ADD(ARPHRD_FCPL,fcpl) 533 __ADD(ARPHRD_FCFABRIC,fcfb_0) 534 __ADD(ARPHRD_FCFABRIC+1,fcfb_1) 535 __ADD(ARPHRD_FCFABRIC+2,fcfb_2) 536 __ADD(ARPHRD_FCFABRIC+3,fcfb_3) 537 __ADD(ARPHRD_FCFABRIC+4,fcfb_4) 538 __ADD(ARPHRD_FCFABRIC+5,fcfb_5) 539 __ADD(ARPHRD_FCFABRIC+6,fcfb_6) 540 __ADD(ARPHRD_FCFABRIC+7,fcfb_7) 541 __ADD(ARPHRD_FCFABRIC+8,fcfb_8) 542 __ADD(ARPHRD_FCFABRIC+9,fcfb_9) 543 __ADD(ARPHRD_FCFABRIC+10,fcfb_10) 544 __ADD(ARPHRD_FCFABRIC+11,fcfb_11) 545 __ADD(ARPHRD_FCFABRIC+12,fcfb_12) 546 __ADD(ARPHRD_IEEE802_TR,tr) 547 __ADD(ARPHRD_IEEE80211,ieee802.11) 548 #ifdef ARPHRD_IEEE80211_PRISM 549 __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism) 550 #endif 551 #ifdef ARPHRD_VOID 552 __ADD(ARPHRD_VOID,void) 553 #endif 554 }; 555 556 char * nl_llproto2str(int llproto, char *buf, size_t len) 557 { 558 return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos)); 559 } 560 561 int nl_str2llproto(const char *name) 562 { 563 return __str2type(name, llprotos, ARRAY_SIZE(llprotos)); 564 } 565 566 /** @} */ 567 568 569 /** 570 * @name Ethernet Protocol Translations 571 * @{ 572 */ 573 574 static struct trans_tbl ether_protos[] = { 575 __ADD(ETH_P_LOOP,loop) 576 __ADD(ETH_P_PUP,pup) 577 __ADD(ETH_P_PUPAT,pupat) 578 __ADD(ETH_P_IP,ip) 579 __ADD(ETH_P_X25,x25) 580 __ADD(ETH_P_ARP,arp) 581 __ADD(ETH_P_BPQ,bpq) 582 __ADD(ETH_P_IEEEPUP,ieeepup) 583 __ADD(ETH_P_IEEEPUPAT,ieeepupat) 584 __ADD(ETH_P_DEC,dec) 585 __ADD(ETH_P_DNA_DL,dna_dl) 586 __ADD(ETH_P_DNA_RC,dna_rc) 587 __ADD(ETH_P_DNA_RT,dna_rt) 588 __ADD(ETH_P_LAT,lat) 589 __ADD(ETH_P_DIAG,diag) 590 __ADD(ETH_P_CUST,cust) 591 __ADD(ETH_P_SCA,sca) 592 __ADD(ETH_P_RARP,rarp) 593 __ADD(ETH_P_ATALK,atalk) 594 __ADD(ETH_P_AARP,aarp) 595 #ifdef ETH_P_8021Q 596 __ADD(ETH_P_8021Q,802.1q) 597 #endif 598 __ADD(ETH_P_IPX,ipx) 599 __ADD(ETH_P_IPV6,ipv6) 600 #ifdef ETH_P_WCCP 601 __ADD(ETH_P_WCCP,wccp) 602 #endif 603 __ADD(ETH_P_PPP_DISC,ppp_disc) 604 __ADD(ETH_P_PPP_SES,ppp_ses) 605 __ADD(ETH_P_MPLS_UC,mpls_uc) 606 __ADD(ETH_P_MPLS_MC,mpls_mc) 607 __ADD(ETH_P_ATMMPOA,atmmpoa) 608 __ADD(ETH_P_ATMFATE,atmfate) 609 __ADD(ETH_P_EDP2,edp2) 610 __ADD(ETH_P_802_3,802.3) 611 __ADD(ETH_P_AX25,ax25) 612 __ADD(ETH_P_ALL,all) 613 __ADD(ETH_P_802_2,802.2) 614 __ADD(ETH_P_SNAP,snap) 615 __ADD(ETH_P_DDCMP,ddcmp) 616 __ADD(ETH_P_WAN_PPP,wan_ppp) 617 __ADD(ETH_P_PPP_MP,ppp_mp) 618 __ADD(ETH_P_LOCALTALK,localtalk) 619 __ADD(ETH_P_PPPTALK,ppptalk) 620 __ADD(ETH_P_TR_802_2,tr_802.2) 621 __ADD(ETH_P_MOBITEX,mobitex) 622 __ADD(ETH_P_CONTROL,control) 623 __ADD(ETH_P_IRDA,irda) 624 __ADD(ETH_P_ECONET,econet) 625 __ADD(ETH_P_HDLC,hdlc) 626 }; 627 628 char *nl_ether_proto2str(int eproto, char *buf, size_t len) 629 { 630 return __type2str(eproto, buf, len, ether_protos, 631 ARRAY_SIZE(ether_protos)); 632 } 633 634 int nl_str2ether_proto(const char *name) 635 { 636 return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos)); 637 } 638 639 /** @} */ 640 641 /** 642 * @name IP Protocol Translations 643 * @{ 644 */ 645 646 char *nl_ip_proto2str(int proto, char *buf, size_t len) 647 { 648 struct protoent *p = getprotobynumber(proto); 649 650 if (p) { 651 snprintf(buf, len, "%s", p->p_name); 652 return buf; 653 } 654 655 snprintf(buf, len, "0x%x", proto); 656 return buf; 657 } 658 659 int nl_str2ip_proto(const char *name) 660 { 661 struct protoent *p = getprotobyname(name); 662 unsigned long l; 663 char *end; 664 665 if (p) 666 return p->p_proto; 667 668 l = strtoul(name, &end, 0); 669 if (l == ULONG_MAX || *end != '\0') 670 return -NLE_OBJ_NOTFOUND; 671 672 return (int) l; 673 } 674 675 /** @} */ 676 677 /** 678 * @name Dumping Helpers 679 * @{ 680 */ 681 682 /** 683 * Handle a new line while dumping 684 * @arg params Dumping parameters 685 * 686 * This function must be called before dumping any onto a 687 * new line. It will ensure proper prefixing as specified 688 * by the dumping parameters. 689 * 690 * @note This function will NOT dump any newlines itself 691 */ 692 void nl_new_line(struct nl_dump_params *params) 693 { 694 params->dp_line++; 695 696 if (params->dp_prefix) { 697 int i; 698 for (i = 0; i < params->dp_prefix; i++) { 699 if (params->dp_fd) 700 fprintf(params->dp_fd, " "); 701 else if (params->dp_buf) 702 strncat(params->dp_buf, " ", 703 params->dp_buflen - 704 sizeof(params->dp_buf) - 1); 705 } 706 } 707 708 if (params->dp_nl_cb) 709 params->dp_nl_cb(params, params->dp_line); 710 } 711 712 static void dump_one(struct nl_dump_params *parms, const char *fmt, 713 va_list args) 714 { 715 if (parms->dp_fd) 716 vfprintf(parms->dp_fd, fmt, args); 717 else if (parms->dp_buf || parms->dp_cb) { 718 char *buf = NULL; 719 vasprintf(&buf, fmt, args); 720 if (parms->dp_cb) 721 parms->dp_cb(parms, buf); 722 else 723 strncat(parms->dp_buf, buf, 724 parms->dp_buflen - strlen(parms->dp_buf) - 1); 725 free(buf); 726 } 727 } 728 729 730 /** 731 * Dump a formatted character string 732 * @arg params Dumping parameters 733 * @arg fmt printf style formatting string 734 * @arg ... Arguments to formatting string 735 * 736 * Dumps a printf style formatting string to the output device 737 * as specified by the dumping parameters. 738 */ 739 void nl_dump(struct nl_dump_params *params, const char *fmt, ...) 740 { 741 va_list args; 742 743 va_start(args, fmt); 744 dump_one(params, fmt, args); 745 va_end(args); 746 } 747 748 void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...) 749 { 750 va_list args; 751 752 nl_new_line(parms); 753 754 va_start(args, fmt); 755 dump_one(parms, fmt, args); 756 va_end(args); 757 } 758 759 760 /** @} */ 761 762 /** @cond SKIP */ 763 764 int __trans_list_add(int i, const char *a, struct nl_list_head *head) 765 { 766 struct trans_list *tl; 767 768 tl = calloc(1, sizeof(*tl)); 769 if (!tl) 770 return -NLE_NOMEM; 771 772 tl->i = i; 773 tl->a = strdup(a); 774 775 nl_list_add_tail(&tl->list, head); 776 777 return 0; 778 } 779 780 void __trans_list_clear(struct nl_list_head *head) 781 { 782 struct trans_list *tl, *next; 783 784 nl_list_for_each_entry_safe(tl, next, head, list) { 785 free(tl->a); 786 free(tl); 787 } 788 } 789 790 char *__type2str(int type, char *buf, size_t len, struct trans_tbl *tbl, 791 size_t tbl_len) 792 { 793 int i; 794 for (i = 0; i < tbl_len; i++) { 795 if (tbl[i].i == type) { 796 snprintf(buf, len, "%s", tbl[i].a); 797 return buf; 798 } 799 } 800 801 snprintf(buf, len, "0x%x", type); 802 return buf; 803 } 804 805 char *__list_type2str(int type, char *buf, size_t len, 806 struct nl_list_head *head) 807 { 808 struct trans_list *tl; 809 810 nl_list_for_each_entry(tl, head, list) { 811 if (tl->i == type) { 812 snprintf(buf, len, "%s", tl->a); 813 return buf; 814 } 815 } 816 817 snprintf(buf, len, "0x%x", type); 818 return buf; 819 } 820 821 char *__flags2str(int flags, char *buf, size_t len, 822 struct trans_tbl *tbl, size_t tbl_len) 823 { 824 int i; 825 int tmp = flags; 826 827 memset(buf, 0, len); 828 829 for (i = 0; i < tbl_len; i++) { 830 if (tbl[i].i & tmp) { 831 tmp &= ~tbl[i].i; 832 strncat(buf, tbl[i].a, len - strlen(buf) - 1); 833 if ((tmp & flags)) 834 strncat(buf, ",", len - strlen(buf) - 1); 835 } 836 } 837 838 return buf; 839 } 840 841 int __str2type(const char *buf, struct trans_tbl *tbl, size_t tbl_len) 842 { 843 unsigned long l; 844 char *end; 845 int i; 846 847 if (*buf == '\0') 848 return -NLE_INVAL; 849 850 for (i = 0; i < tbl_len; i++) 851 if (!strcasecmp(tbl[i].a, buf)) 852 return tbl[i].i; 853 854 l = strtoul(buf, &end, 0); 855 if (l == ULONG_MAX || *end != '\0') 856 return -NLE_OBJ_NOTFOUND; 857 858 return (int) l; 859 } 860 861 int __list_str2type(const char *buf, struct nl_list_head *head) 862 { 863 struct trans_list *tl; 864 unsigned long l; 865 char *end; 866 867 if (*buf == '\0') 868 return -NLE_INVAL; 869 870 nl_list_for_each_entry(tl, head, list) { 871 if (!strcasecmp(tl->a, buf)) 872 return tl->i; 873 } 874 875 l = strtoul(buf, &end, 0); 876 if (l == ULONG_MAX || *end != '\0') 877 return -NLE_OBJ_NOTFOUND; 878 879 return (int) l; 880 } 881 882 int __str2flags(const char *buf, struct trans_tbl *tbl, size_t tbl_len) 883 { 884 int i, flags = 0, len; 885 char *p = (char *) buf, *t; 886 887 for (;;) { 888 if (*p == ' ') 889 p++; 890 891 t = strchr(p, ','); 892 len = t ? t - p : strlen(p); 893 for (i = 0; i < tbl_len; i++) 894 if (!strncasecmp(tbl[i].a, p, len)) 895 flags |= tbl[i].i; 896 897 if (!t) 898 return flags; 899 900 p = ++t; 901 } 902 903 return 0; 904 } 905 906 void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params) 907 { 908 int type = params->dp_type; 909 910 if (type < 0 || type > NL_DUMP_MAX) 911 BUG(); 912 913 params->dp_line = 0; 914 915 if (params->dp_dump_msgtype) { 916 #if 0 917 /* XXX */ 918 char buf[64]; 919 920 dp_dump_line(params, 0, "%s ", 921 nl_cache_mngt_type2name(obj->ce_ops, 922 obj->ce_ops->co_protocol, 923 obj->ce_msgtype, 924 buf, sizeof(buf))); 925 #endif 926 params->dp_pre_dump = 1; 927 } 928 929 if (obj->ce_ops->oo_dump[type]) 930 obj->ce_ops->oo_dump[type](obj, params); 931 } 932 933 /** @endcond */ 934 935 /** @} */ 936