Home | History | Annotate | Download | only in lib
      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