libnl 2.0
|
00001 /* 00002 * lib/utils.c Utility Functions 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup core 00014 * @defgroup utils Utilities 00015 * @{ 00016 */ 00017 00018 #include <netlink-local.h> 00019 #include <netlink/netlink.h> 00020 #include <netlink/utils.h> 00021 #include <linux/socket.h> 00022 00023 /** 00024 * Debug level 00025 */ 00026 int nl_debug = 0; 00027 00028 struct nl_dump_params nl_debug_dp = { 00029 .dp_type = NL_DUMP_DETAILS, 00030 }; 00031 00032 static void __init nl_debug_init(void) 00033 { 00034 char *nldbg, *end; 00035 00036 if ((nldbg = getenv("NLDBG"))) { 00037 long level = strtol(nldbg, &end, 0); 00038 if (nldbg != end) 00039 nl_debug = level; 00040 } 00041 00042 nl_debug_dp.dp_fd = stderr; 00043 } 00044 00045 int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) 00046 { 00047 FILE *fd; 00048 char buf[128]; 00049 00050 fd = fopen(path, "r"); 00051 if (fd == NULL) 00052 return -nl_syserr2nlerr(errno); 00053 00054 while (fgets(buf, sizeof(buf), fd)) { 00055 int goodlen, err; 00056 long num; 00057 char *end; 00058 00059 if (*buf == '#' || *buf == '\n' || *buf == '\r') 00060 continue; 00061 00062 num = strtol(buf, &end, 0); 00063 if (end == buf) 00064 return -NLE_INVAL; 00065 00066 if (num == LONG_MIN || num == LONG_MAX) 00067 return -NLE_RANGE; 00068 00069 while (*end == ' ' || *end == '\t') 00070 end++; 00071 00072 goodlen = strcspn(end, "#\r\n\t "); 00073 if (goodlen == 0) 00074 return -NLE_INVAL; 00075 00076 end[goodlen] = '\0'; 00077 00078 err = cb(num, end); 00079 if (err < 0) 00080 return err; 00081 } 00082 00083 fclose(fd); 00084 00085 return 0; 00086 } 00087 00088 /** 00089 * @name Unit Pretty-Printing 00090 * @{ 00091 */ 00092 00093 /** 00094 * Cancel down a byte counter 00095 * @arg l byte counter 00096 * @arg unit destination unit pointer 00097 * 00098 * Cancels down a byte counter until it reaches a reasonable 00099 * unit. The chosen unit is assigned to \a unit. 00100 * 00101 * @return The cancelled down byte counter in the new unit. 00102 */ 00103 double nl_cancel_down_bytes(unsigned long long l, char **unit) 00104 { 00105 if (l >= 1099511627776LL) { 00106 *unit = "TiB"; 00107 return ((double) l) / 1099511627776LL; 00108 } else if (l >= 1073741824) { 00109 *unit = "GiB"; 00110 return ((double) l) / 1073741824; 00111 } else if (l >= 1048576) { 00112 *unit = "MiB"; 00113 return ((double) l) / 1048576; 00114 } else if (l >= 1024) { 00115 *unit = "KiB"; 00116 return ((double) l) / 1024; 00117 } else { 00118 *unit = "B"; 00119 return (double) l; 00120 } 00121 } 00122 00123 /** 00124 * Cancel down a bit counter 00125 * @arg l bit counter 00126 * @arg unit destination unit pointer 00127 * 00128 * Cancels downa bit counter until it reaches a reasonable 00129 * unit. The chosen unit is assigned to \a unit. 00130 * 00131 * @return The cancelled down bit counter in the new unit. 00132 */ 00133 double nl_cancel_down_bits(unsigned long long l, char **unit) 00134 { 00135 if (l >= 1099511627776ULL) { 00136 *unit = "Tbit"; 00137 return ((double) l) / 1099511627776ULL; 00138 } else if (l >= 1073741824) { 00139 *unit = "Gbit"; 00140 return ((double) l) / 1073741824; 00141 } else if (l >= 1048576) { 00142 *unit = "Mbit"; 00143 return ((double) l) / 1048576; 00144 } else if (l >= 1024) { 00145 *unit = "Kbit"; 00146 return ((double) l) / 1024; 00147 } else { 00148 *unit = "bit"; 00149 return (double) l; 00150 } 00151 00152 } 00153 00154 /** 00155 * Cancel down a micro second value 00156 * @arg l micro seconds 00157 * @arg unit destination unit pointer 00158 * 00159 * Cancels down a microsecond counter until it reaches a 00160 * reasonable unit. The chosen unit is assigned to \a unit. 00161 * 00162 * @return The cancelled down microsecond in the new unit 00163 */ 00164 double nl_cancel_down_us(uint32_t l, char **unit) 00165 { 00166 if (l >= 1000000) { 00167 *unit = "s"; 00168 return ((double) l) / 1000000; 00169 } else if (l >= 1000) { 00170 *unit = "ms"; 00171 return ((double) l) / 1000; 00172 } else { 00173 *unit = "us"; 00174 return (double) l; 00175 } 00176 } 00177 00178 /** @} */ 00179 00180 /** 00181 * @name Generic Unit Translations 00182 * @{ 00183 */ 00184 00185 /** 00186 * Convert a character string to a size 00187 * @arg str size encoded as character string 00188 * 00189 * Converts the specified size as character to the corresponding 00190 * number of bytes. 00191 * 00192 * Supported formats are: 00193 * - b,kb/k,m/mb,gb/g for bytes 00194 * - bit,kbit/mbit/gbit 00195 * 00196 * @return The number of bytes or -1 if the string is unparseable 00197 */ 00198 long nl_size2int(const char *str) 00199 { 00200 char *p; 00201 long l = strtol(str, &p, 0); 00202 if (p == str) 00203 return -NLE_INVAL; 00204 00205 if (*p) { 00206 if (!strcasecmp(p, "kb") || !strcasecmp(p, "k")) 00207 l *= 1024; 00208 else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g")) 00209 l *= 1024*1024*1024; 00210 else if (!strcasecmp(p, "gbit")) 00211 l *= 1024*1024*1024/8; 00212 else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m")) 00213 l *= 1024*1024; 00214 else if (!strcasecmp(p, "mbit")) 00215 l *= 1024*1024/8; 00216 else if (!strcasecmp(p, "kbit")) 00217 l *= 1024/8; 00218 else if (!strcasecmp(p, "bit")) 00219 l /= 8; 00220 else if (strcasecmp(p, "b") != 0) 00221 return -NLE_INVAL; 00222 } 00223 00224 return l; 00225 } 00226 00227 /** 00228 * Convert a character string to a probability 00229 * @arg str probability encoded as character string 00230 * 00231 * Converts the specified probability as character to the 00232 * corresponding probability number. 00233 * 00234 * Supported formats are: 00235 * - 0.0-1.0 00236 * - 0%-100% 00237 * 00238 * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX 00239 */ 00240 long nl_prob2int(const char *str) 00241 { 00242 char *p; 00243 double d = strtod(str, &p); 00244 00245 if (p == str) 00246 return -NLE_INVAL; 00247 00248 if (d > 1.0) 00249 d /= 100.0f; 00250 00251 if (d > 1.0f || d < 0.0f) 00252 return -NLE_RANGE; 00253 00254 if (*p && strcmp(p, "%") != 0) 00255 return -NLE_INVAL; 00256 00257 return rint(d * NL_PROB_MAX); 00258 } 00259 00260 /** @} */ 00261 00262 /** 00263 * @name Time Translations 00264 * @{ 00265 */ 00266 00267 #ifdef USER_HZ 00268 static uint32_t user_hz = USER_HZ; 00269 #else 00270 static uint32_t user_hz = 100; 00271 #endif 00272 00273 static double ticks_per_usec = 1.0f; 00274 00275 /* Retrieves the configured HZ and ticks/us value in the kernel. 00276 * The value is cached. Supported ways of getting it: 00277 * 00278 * 1) environment variable 00279 * 2) /proc/net/psched and sysconf 00280 * 00281 * Supports the environment variables: 00282 * PROC_NET_PSCHED - may point to psched file in /proc 00283 * PROC_ROOT - may point to /proc fs */ 00284 static void __init get_psched_settings(void) 00285 { 00286 char name[FILENAME_MAX]; 00287 FILE *fd; 00288 int got_hz = 0; 00289 00290 if (getenv("HZ")) { 00291 long hz = strtol(getenv("HZ"), NULL, 0); 00292 00293 if (LONG_MIN != hz && LONG_MAX != hz) { 00294 user_hz = hz; 00295 got_hz = 1; 00296 } 00297 } 00298 00299 if (!got_hz) 00300 user_hz = sysconf(_SC_CLK_TCK); 00301 00302 if (getenv("TICKS_PER_USEC")) { 00303 double t = strtod(getenv("TICKS_PER_USEC"), NULL); 00304 ticks_per_usec = t; 00305 } 00306 else { 00307 if (getenv("PROC_NET_PSCHED")) 00308 snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED")); 00309 else if (getenv("PROC_ROOT")) 00310 snprintf(name, sizeof(name), "%s/net/psched", 00311 getenv("PROC_ROOT")); 00312 else 00313 strncpy(name, "/proc/net/psched", sizeof(name) - 1); 00314 00315 if ((fd = fopen(name, "r"))) { 00316 uint32_t tick, us; 00317 /* the file contains 4 hexadecimals, but we just use 00318 the first two of them */ 00319 fscanf(fd, "%08x %08x", &tick, &us); 00320 ticks_per_usec = (double)tick/(double)us; 00321 fclose(fd); 00322 } 00323 } 00324 } 00325 00326 00327 /** 00328 * Return the value of HZ 00329 */ 00330 int nl_get_hz(void) 00331 { 00332 return user_hz; 00333 } 00334 00335 00336 /** 00337 * Convert micro seconds to ticks 00338 * @arg us micro seconds 00339 * @return number of ticks 00340 */ 00341 uint32_t nl_us2ticks(uint32_t us) 00342 { 00343 return us * ticks_per_usec; 00344 } 00345 00346 00347 /** 00348 * Convert ticks to micro seconds 00349 * @arg ticks number of ticks 00350 * @return microseconds 00351 */ 00352 uint32_t nl_ticks2us(uint32_t ticks) 00353 { 00354 return ticks / ticks_per_usec; 00355 } 00356 00357 int nl_str2msec(const char *str, uint64_t *result) 00358 { 00359 uint64_t total = 0, l; 00360 int plen; 00361 char *p; 00362 00363 do { 00364 l = strtoul(str, &p, 0); 00365 if (p == str) 00366 return -NLE_INVAL; 00367 else if (*p) { 00368 plen = strcspn(p, " \t"); 00369 00370 if (!plen) 00371 total += l; 00372 else if (!strncasecmp(p, "sec", plen)) 00373 total += (l * 1000); 00374 else if (!strncasecmp(p, "min", plen)) 00375 total += (l * 1000*60); 00376 else if (!strncasecmp(p, "hour", plen)) 00377 total += (l * 1000*60*60); 00378 else if (!strncasecmp(p, "day", plen)) 00379 total += (l * 1000*60*60*24); 00380 else 00381 return -NLE_INVAL; 00382 00383 str = p + plen; 00384 } else 00385 total += l; 00386 } while (*str && *p); 00387 00388 *result = total; 00389 00390 return 0; 00391 } 00392 00393 /** 00394 * Convert milliseconds to a character string 00395 * @arg msec number of milliseconds 00396 * @arg buf destination buffer 00397 * @arg len buffer length 00398 * 00399 * Converts milliseconds to a character string split up in days, hours, 00400 * minutes, seconds, and milliseconds and stores it in the specified 00401 * destination buffer. 00402 * 00403 * @return The destination buffer. 00404 */ 00405 char * nl_msec2str(uint64_t msec, char *buf, size_t len) 00406 { 00407 int i, split[5]; 00408 char *units[] = {"d", "h", "m", "s", "msec"}; 00409 00410 #define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit 00411 _SPLIT(0, 86400000); /* days */ 00412 _SPLIT(1, 3600000); /* hours */ 00413 _SPLIT(2, 60000); /* minutes */ 00414 _SPLIT(3, 1000); /* seconds */ 00415 #undef _SPLIT 00416 split[4] = msec; 00417 00418 memset(buf, 0, len); 00419 00420 for (i = 0; i < ARRAY_SIZE(split); i++) { 00421 if (split[i] > 0) { 00422 char t[64]; 00423 snprintf(t, sizeof(t), "%s%d%s", 00424 strlen(buf) ? " " : "", split[i], units[i]); 00425 strncat(buf, t, len - strlen(buf) - 1); 00426 } 00427 } 00428 00429 return buf; 00430 } 00431 00432 /** @} */ 00433 00434 /** 00435 * @name Netlink Family Translations 00436 * @{ 00437 */ 00438 00439 static struct trans_tbl nlfamilies[] = { 00440 __ADD(NETLINK_ROUTE,route) 00441 __ADD(NETLINK_USERSOCK,usersock) 00442 __ADD(NETLINK_FIREWALL,firewall) 00443 __ADD(NETLINK_INET_DIAG,inetdiag) 00444 __ADD(NETLINK_NFLOG,nflog) 00445 __ADD(NETLINK_XFRM,xfrm) 00446 __ADD(NETLINK_SELINUX,selinux) 00447 __ADD(NETLINK_ISCSI,iscsi) 00448 __ADD(NETLINK_AUDIT,audit) 00449 __ADD(NETLINK_FIB_LOOKUP,fib_lookup) 00450 __ADD(NETLINK_CONNECTOR,connector) 00451 __ADD(NETLINK_NETFILTER,netfilter) 00452 __ADD(NETLINK_IP6_FW,ip6_fw) 00453 __ADD(NETLINK_DNRTMSG,dnrtmsg) 00454 __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent) 00455 __ADD(NETLINK_GENERIC,generic) 00456 __ADD(NETLINK_SCSITRANSPORT,scsitransport) 00457 __ADD(NETLINK_ECRYPTFS,ecryptfs) 00458 }; 00459 00460 char * nl_nlfamily2str(int family, char *buf, size_t size) 00461 { 00462 return __type2str(family, buf, size, nlfamilies, 00463 ARRAY_SIZE(nlfamilies)); 00464 } 00465 00466 int nl_str2nlfamily(const char *name) 00467 { 00468 return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies)); 00469 } 00470 00471 /** 00472 * @} 00473 */ 00474 00475 /** 00476 * @name Link Layer Protocol Translations 00477 * @{ 00478 */ 00479 00480 static struct trans_tbl llprotos[] = { 00481 {0, "generic"}, 00482 __ADD(ARPHRD_ETHER,ether) 00483 __ADD(ARPHRD_EETHER,eether) 00484 __ADD(ARPHRD_AX25,ax25) 00485 __ADD(ARPHRD_PRONET,pronet) 00486 __ADD(ARPHRD_CHAOS,chaos) 00487 __ADD(ARPHRD_IEEE802,ieee802) 00488 __ADD(ARPHRD_ARCNET,arcnet) 00489 __ADD(ARPHRD_APPLETLK,atalk) 00490 __ADD(ARPHRD_DLCI,dlci) 00491 __ADD(ARPHRD_ATM,atm) 00492 __ADD(ARPHRD_METRICOM,metricom) 00493 __ADD(ARPHRD_IEEE1394,ieee1394) 00494 #ifdef ARPHRD_EUI64 00495 __ADD(ARPHRD_EUI64,eui64) 00496 #endif 00497 __ADD(ARPHRD_INFINIBAND,infiniband) 00498 __ADD(ARPHRD_SLIP,slip) 00499 __ADD(ARPHRD_CSLIP,cslip) 00500 __ADD(ARPHRD_SLIP6,slip6) 00501 __ADD(ARPHRD_CSLIP6,cslip6) 00502 __ADD(ARPHRD_RSRVD,rsrvd) 00503 __ADD(ARPHRD_ADAPT,adapt) 00504 __ADD(ARPHRD_ROSE,rose) 00505 __ADD(ARPHRD_X25,x25) 00506 #ifdef ARPHRD_HWX25 00507 __ADD(ARPHRD_HWX25,hwx25) 00508 #endif 00509 __ADD(ARPHRD_PPP,ppp) 00510 __ADD(ARPHRD_HDLC,hdlc) 00511 __ADD(ARPHRD_LAPB,lapb) 00512 __ADD(ARPHRD_DDCMP,ddcmp) 00513 __ADD(ARPHRD_RAWHDLC,rawhdlc) 00514 __ADD(ARPHRD_TUNNEL,ipip) 00515 __ADD(ARPHRD_TUNNEL6,tunnel6) 00516 __ADD(ARPHRD_FRAD,frad) 00517 __ADD(ARPHRD_SKIP,skip) 00518 __ADD(ARPHRD_LOOPBACK,loopback) 00519 __ADD(ARPHRD_LOCALTLK,localtlk) 00520 __ADD(ARPHRD_FDDI,fddi) 00521 __ADD(ARPHRD_BIF,bif) 00522 __ADD(ARPHRD_SIT,sit) 00523 __ADD(ARPHRD_IPDDP,ip/ddp) 00524 __ADD(ARPHRD_IPGRE,gre) 00525 __ADD(ARPHRD_PIMREG,pimreg) 00526 __ADD(ARPHRD_HIPPI,hippi) 00527 __ADD(ARPHRD_ASH,ash) 00528 __ADD(ARPHRD_ECONET,econet) 00529 __ADD(ARPHRD_IRDA,irda) 00530 __ADD(ARPHRD_FCPP,fcpp) 00531 __ADD(ARPHRD_FCAL,fcal) 00532 __ADD(ARPHRD_FCPL,fcpl) 00533 __ADD(ARPHRD_FCFABRIC,fcfb_0) 00534 __ADD(ARPHRD_FCFABRIC+1,fcfb_1) 00535 __ADD(ARPHRD_FCFABRIC+2,fcfb_2) 00536 __ADD(ARPHRD_FCFABRIC+3,fcfb_3) 00537 __ADD(ARPHRD_FCFABRIC+4,fcfb_4) 00538 __ADD(ARPHRD_FCFABRIC+5,fcfb_5) 00539 __ADD(ARPHRD_FCFABRIC+6,fcfb_6) 00540 __ADD(ARPHRD_FCFABRIC+7,fcfb_7) 00541 __ADD(ARPHRD_FCFABRIC+8,fcfb_8) 00542 __ADD(ARPHRD_FCFABRIC+9,fcfb_9) 00543 __ADD(ARPHRD_FCFABRIC+10,fcfb_10) 00544 __ADD(ARPHRD_FCFABRIC+11,fcfb_11) 00545 __ADD(ARPHRD_FCFABRIC+12,fcfb_12) 00546 __ADD(ARPHRD_IEEE802_TR,tr) 00547 __ADD(ARPHRD_IEEE80211,ieee802.11) 00548 #ifdef ARPHRD_IEEE80211_PRISM 00549 __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism) 00550 #endif 00551 #ifdef ARPHRD_VOID 00552 __ADD(ARPHRD_VOID,void) 00553 #endif 00554 }; 00555 00556 char * nl_llproto2str(int llproto, char *buf, size_t len) 00557 { 00558 return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos)); 00559 } 00560 00561 int nl_str2llproto(const char *name) 00562 { 00563 return __str2type(name, llprotos, ARRAY_SIZE(llprotos)); 00564 } 00565 00566 /** @} */ 00567 00568 00569 /** 00570 * @name Ethernet Protocol Translations 00571 * @{ 00572 */ 00573 00574 static struct trans_tbl ether_protos[] = { 00575 __ADD(ETH_P_LOOP,loop) 00576 __ADD(ETH_P_PUP,pup) 00577 __ADD(ETH_P_PUPAT,pupat) 00578 __ADD(ETH_P_IP,ip) 00579 __ADD(ETH_P_X25,x25) 00580 __ADD(ETH_P_ARP,arp) 00581 __ADD(ETH_P_BPQ,bpq) 00582 __ADD(ETH_P_IEEEPUP,ieeepup) 00583 __ADD(ETH_P_IEEEPUPAT,ieeepupat) 00584 __ADD(ETH_P_DEC,dec) 00585 __ADD(ETH_P_DNA_DL,dna_dl) 00586 __ADD(ETH_P_DNA_RC,dna_rc) 00587 __ADD(ETH_P_DNA_RT,dna_rt) 00588 __ADD(ETH_P_LAT,lat) 00589 __ADD(ETH_P_DIAG,diag) 00590 __ADD(ETH_P_CUST,cust) 00591 __ADD(ETH_P_SCA,sca) 00592 __ADD(ETH_P_RARP,rarp) 00593 __ADD(ETH_P_ATALK,atalk) 00594 __ADD(ETH_P_AARP,aarp) 00595 #ifdef ETH_P_8021Q 00596 __ADD(ETH_P_8021Q,802.1q) 00597 #endif 00598 __ADD(ETH_P_IPX,ipx) 00599 __ADD(ETH_P_IPV6,ipv6) 00600 #ifdef ETH_P_WCCP 00601 __ADD(ETH_P_WCCP,wccp) 00602 #endif 00603 __ADD(ETH_P_PPP_DISC,ppp_disc) 00604 __ADD(ETH_P_PPP_SES,ppp_ses) 00605 __ADD(ETH_P_MPLS_UC,mpls_uc) 00606 __ADD(ETH_P_MPLS_MC,mpls_mc) 00607 __ADD(ETH_P_ATMMPOA,atmmpoa) 00608 __ADD(ETH_P_ATMFATE,atmfate) 00609 __ADD(ETH_P_EDP2,edp2) 00610 __ADD(ETH_P_802_3,802.3) 00611 __ADD(ETH_P_AX25,ax25) 00612 __ADD(ETH_P_ALL,all) 00613 __ADD(ETH_P_802_2,802.2) 00614 __ADD(ETH_P_SNAP,snap) 00615 __ADD(ETH_P_DDCMP,ddcmp) 00616 __ADD(ETH_P_WAN_PPP,wan_ppp) 00617 __ADD(ETH_P_PPP_MP,ppp_mp) 00618 __ADD(ETH_P_LOCALTALK,localtalk) 00619 __ADD(ETH_P_PPPTALK,ppptalk) 00620 __ADD(ETH_P_TR_802_2,tr_802.2) 00621 __ADD(ETH_P_MOBITEX,mobitex) 00622 __ADD(ETH_P_CONTROL,control) 00623 __ADD(ETH_P_IRDA,irda) 00624 __ADD(ETH_P_ECONET,econet) 00625 __ADD(ETH_P_HDLC,hdlc) 00626 }; 00627 00628 char *nl_ether_proto2str(int eproto, char *buf, size_t len) 00629 { 00630 return __type2str(eproto, buf, len, ether_protos, 00631 ARRAY_SIZE(ether_protos)); 00632 } 00633 00634 int nl_str2ether_proto(const char *name) 00635 { 00636 return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos)); 00637 } 00638 00639 /** @} */ 00640 00641 /** 00642 * @name IP Protocol Translations 00643 * @{ 00644 */ 00645 00646 char *nl_ip_proto2str(int proto, char *buf, size_t len) 00647 { 00648 struct protoent *p = getprotobynumber(proto); 00649 00650 if (p) { 00651 snprintf(buf, len, "%s", p->p_name); 00652 return buf; 00653 } 00654 00655 snprintf(buf, len, "0x%x", proto); 00656 return buf; 00657 } 00658 00659 int nl_str2ip_proto(const char *name) 00660 { 00661 struct protoent *p = getprotobyname(name); 00662 unsigned long l; 00663 char *end; 00664 00665 if (p) 00666 return p->p_proto; 00667 00668 l = strtoul(name, &end, 0); 00669 if (l == ULONG_MAX || *end != '\0') 00670 return -NLE_OBJ_NOTFOUND; 00671 00672 return (int) l; 00673 } 00674 00675 /** @} */ 00676 00677 /** 00678 * @name Dumping Helpers 00679 * @{ 00680 */ 00681 00682 /** 00683 * Handle a new line while dumping 00684 * @arg params Dumping parameters 00685 * 00686 * This function must be called before dumping any onto a 00687 * new line. It will ensure proper prefixing as specified 00688 * by the dumping parameters. 00689 * 00690 * @note This function will NOT dump any newlines itself 00691 */ 00692 void nl_new_line(struct nl_dump_params *params) 00693 { 00694 params->dp_line++; 00695 00696 if (params->dp_prefix) { 00697 int i; 00698 for (i = 0; i < params->dp_prefix; i++) { 00699 if (params->dp_fd) 00700 fprintf(params->dp_fd, " "); 00701 else if (params->dp_buf) 00702 strncat(params->dp_buf, " ", 00703 params->dp_buflen - 00704 sizeof(params->dp_buf) - 1); 00705 } 00706 } 00707 00708 if (params->dp_nl_cb) 00709 params->dp_nl_cb(params, params->dp_line); 00710 } 00711 00712 static void dump_one(struct nl_dump_params *parms, const char *fmt, 00713 va_list args) 00714 { 00715 if (parms->dp_fd) 00716 vfprintf(parms->dp_fd, fmt, args); 00717 else if (parms->dp_buf || parms->dp_cb) { 00718 char *buf = NULL; 00719 vasprintf(&buf, fmt, args); 00720 if (parms->dp_cb) 00721 parms->dp_cb(parms, buf); 00722 else 00723 strncat(parms->dp_buf, buf, 00724 parms->dp_buflen - strlen(parms->dp_buf) - 1); 00725 free(buf); 00726 } 00727 } 00728 00729 00730 /** 00731 * Dump a formatted character string 00732 * @arg params Dumping parameters 00733 * @arg fmt printf style formatting string 00734 * @arg ... Arguments to formatting string 00735 * 00736 * Dumps a printf style formatting string to the output device 00737 * as specified by the dumping parameters. 00738 */ 00739 void nl_dump(struct nl_dump_params *params, const char *fmt, ...) 00740 { 00741 va_list args; 00742 00743 va_start(args, fmt); 00744 dump_one(params, fmt, args); 00745 va_end(args); 00746 } 00747 00748 void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...) 00749 { 00750 va_list args; 00751 00752 nl_new_line(parms); 00753 00754 va_start(args, fmt); 00755 dump_one(parms, fmt, args); 00756 va_end(args); 00757 } 00758 00759 00760 /** @} */ 00761 00762 /** @cond SKIP */ 00763 00764 int __trans_list_add(int i, const char *a, struct nl_list_head *head) 00765 { 00766 struct trans_list *tl; 00767 00768 tl = calloc(1, sizeof(*tl)); 00769 if (!tl) 00770 return -NLE_NOMEM; 00771 00772 tl->i = i; 00773 tl->a = strdup(a); 00774 00775 nl_list_add_tail(&tl->list, head); 00776 00777 return 0; 00778 } 00779 00780 void __trans_list_clear(struct nl_list_head *head) 00781 { 00782 struct trans_list *tl, *next; 00783 00784 nl_list_for_each_entry_safe(tl, next, head, list) { 00785 free(tl->a); 00786 free(tl); 00787 } 00788 } 00789 00790 char *__type2str(int type, char *buf, size_t len, struct trans_tbl *tbl, 00791 size_t tbl_len) 00792 { 00793 int i; 00794 for (i = 0; i < tbl_len; i++) { 00795 if (tbl[i].i == type) { 00796 snprintf(buf, len, "%s", tbl[i].a); 00797 return buf; 00798 } 00799 } 00800 00801 snprintf(buf, len, "0x%x", type); 00802 return buf; 00803 } 00804 00805 char *__list_type2str(int type, char *buf, size_t len, 00806 struct nl_list_head *head) 00807 { 00808 struct trans_list *tl; 00809 00810 nl_list_for_each_entry(tl, head, list) { 00811 if (tl->i == type) { 00812 snprintf(buf, len, "%s", tl->a); 00813 return buf; 00814 } 00815 } 00816 00817 snprintf(buf, len, "0x%x", type); 00818 return buf; 00819 } 00820 00821 char *__flags2str(int flags, char *buf, size_t len, 00822 struct trans_tbl *tbl, size_t tbl_len) 00823 { 00824 int i; 00825 int tmp = flags; 00826 00827 memset(buf, 0, len); 00828 00829 for (i = 0; i < tbl_len; i++) { 00830 if (tbl[i].i & tmp) { 00831 tmp &= ~tbl[i].i; 00832 strncat(buf, tbl[i].a, len - strlen(buf) - 1); 00833 if ((tmp & flags)) 00834 strncat(buf, ",", len - strlen(buf) - 1); 00835 } 00836 } 00837 00838 return buf; 00839 } 00840 00841 int __str2type(const char *buf, struct trans_tbl *tbl, size_t tbl_len) 00842 { 00843 unsigned long l; 00844 char *end; 00845 int i; 00846 00847 if (*buf == '\0') 00848 return -NLE_INVAL; 00849 00850 for (i = 0; i < tbl_len; i++) 00851 if (!strcasecmp(tbl[i].a, buf)) 00852 return tbl[i].i; 00853 00854 l = strtoul(buf, &end, 0); 00855 if (l == ULONG_MAX || *end != '\0') 00856 return -NLE_OBJ_NOTFOUND; 00857 00858 return (int) l; 00859 } 00860 00861 int __list_str2type(const char *buf, struct nl_list_head *head) 00862 { 00863 struct trans_list *tl; 00864 unsigned long l; 00865 char *end; 00866 00867 if (*buf == '\0') 00868 return -NLE_INVAL; 00869 00870 nl_list_for_each_entry(tl, head, list) { 00871 if (!strcasecmp(tl->a, buf)) 00872 return tl->i; 00873 } 00874 00875 l = strtoul(buf, &end, 0); 00876 if (l == ULONG_MAX || *end != '\0') 00877 return -NLE_OBJ_NOTFOUND; 00878 00879 return (int) l; 00880 } 00881 00882 int __str2flags(const char *buf, struct trans_tbl *tbl, size_t tbl_len) 00883 { 00884 int i, flags = 0, len; 00885 char *p = (char *) buf, *t; 00886 00887 for (;;) { 00888 if (*p == ' ') 00889 p++; 00890 00891 t = strchr(p, ','); 00892 len = t ? t - p : strlen(p); 00893 for (i = 0; i < tbl_len; i++) 00894 if (!strncasecmp(tbl[i].a, p, len)) 00895 flags |= tbl[i].i; 00896 00897 if (!t) 00898 return flags; 00899 00900 p = ++t; 00901 } 00902 00903 return 0; 00904 } 00905 00906 void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params) 00907 { 00908 int type = params->dp_type; 00909 00910 if (type < 0 || type > NL_DUMP_MAX) 00911 BUG(); 00912 00913 params->dp_line = 0; 00914 00915 if (params->dp_dump_msgtype) { 00916 #if 0 00917 /* XXX */ 00918 char buf[64]; 00919 00920 dp_dump_line(params, 0, "%s ", 00921 nl_cache_mngt_type2name(obj->ce_ops, 00922 obj->ce_ops->co_protocol, 00923 obj->ce_msgtype, 00924 buf, sizeof(buf))); 00925 #endif 00926 params->dp_pre_dump = 1; 00927 } 00928 00929 if (obj->ce_ops->oo_dump[type]) 00930 obj->ce_ops->oo_dump[type](obj, params); 00931 } 00932 00933 /** @endcond */ 00934 00935 /** @} */