/build/buildd/libnl-1.0~pre6/lib/utils.c

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-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @defgroup utils Utilities
00014  * @{
00015  */
00016 
00017 #include <netlink-local.h>
00018 #include <netlink/netlink.h>
00019 #include <netlink/utils.h>
00020 #include <linux/socket.h>
00021 
00022 /**
00023  * Debug level
00024  */
00025 int nl_debug = 0;
00026 
00027 /**
00028  * @name Error Code Helpers
00029  * @{
00030  */
00031 
00032 static char *errbuf;
00033 static int nlerrno;
00034 
00035 /** @cond SKIP */
00036 int __nl_error(int err, const char *file, unsigned int line, const char *func,
00037                const char *fmt, ...)
00038 {
00039         char *user_err;
00040         va_list args;
00041 
00042         if (errbuf) {
00043                 free(errbuf);
00044                 errbuf = NULL;
00045         }
00046 
00047         nlerrno = err;
00048 
00049         if (fmt) {
00050                 va_start(args, fmt);
00051                 vasprintf(&user_err, fmt, args);
00052                 va_end(args);
00053         }
00054 
00055 #ifdef VERBOSE_ERRORS
00056         asprintf(&errbuf, "%s:%u:%s: %s (errno = %s)",
00057                  file, line, func, fmt ? user_err : "", strerror(err));
00058 #else
00059         asprintf(&errbuf, "%s (errno = %s)",
00060                  fmt ? user_err : "", strerror(err));
00061 #endif
00062 
00063         if (fmt)
00064                 free(user_err);
00065 
00066         return -err;
00067 }
00068 
00069 int nl_get_errno(void)
00070 {
00071         return nlerrno;
00072 }
00073 
00074 /** @endcond */
00075 
00076 /**
00077  * Return error message for an error code
00078  * @return error message
00079  */
00080 char *nl_geterror(void)
00081 {
00082         if (errbuf)
00083                 return errbuf;
00084 
00085         if (nlerrno)
00086                 return strerror(nlerrno);
00087 
00088         return "Sucess\n";
00089 }
00090 
00091 /** @} */
00092 
00093 /**
00094  * @name Unit Pretty-Printing
00095  * @{
00096  */
00097 
00098 /**
00099  * Cancel down a byte counter
00100  * @arg l               byte counter
00101  * @arg unit            destination unit pointer
00102  *
00103  * Cancels down a byte counter until it reaches a reasonable
00104  * unit. The chosen unit is assigned to \a unit.
00105  * 
00106  * @return The cancelled down byte counter in the new unit.
00107  */
00108 double nl_cancel_down_bytes(unsigned long long l, char **unit)
00109 {
00110         if (l >= 1099511627776LL) {
00111                 *unit = "TiB";
00112                 return ((double) l) / 1099511627776LL;
00113         } else if (l >= 1073741824) {
00114                 *unit = "GiB";
00115                 return ((double) l) / 1073741824;
00116         } else if (l >= 1048576) {
00117                 *unit = "MiB";
00118                 return ((double) l) / 1048576;
00119         } else if (l >= 1024) {
00120                 *unit = "KiB";
00121                 return ((double) l) / 1024;
00122         } else {
00123                 *unit = "B";
00124                 return (double) l;
00125         }
00126 }
00127 
00128 /**
00129  * Cancel down a bit counter
00130  * @arg l               bit counter
00131  * @arg unit            destination unit pointer
00132  *
00133  * Cancels downa bit counter until it reaches a reasonable
00134  * unit. The chosen unit is assigned to \a unit.
00135  *
00136  * @return The cancelled down bit counter in the new unit.
00137  */
00138 double nl_cancel_down_bits(unsigned long long l, char **unit)
00139 {
00140         if (l >= 1099511627776ULL) {
00141                 *unit = "Tbit";
00142                 return ((double) l) / 1099511627776ULL;
00143         } else if (l >= 1073741824) {
00144                 *unit = "Gbit";
00145                 return ((double) l) / 1073741824;
00146         } else if (l >= 1048576) {
00147                 *unit = "Mbit";
00148                 return ((double) l) / 1048576;
00149         } else if (l >= 1024) {
00150                 *unit = "Kbit";
00151                 return ((double) l) / 1024;
00152         } else {
00153                 *unit = "bit";
00154                 return (double) l;
00155         }
00156                 
00157 }
00158 
00159 /**
00160  * Cancel down a micro second value
00161  * @arg l               micro seconds
00162  * @arg unit            destination unit pointer
00163  *
00164  * Cancels down a microsecond counter until it reaches a
00165  * reasonable unit. The chosen unit is assigned to \a unit.
00166  *
00167  * @return The cancelled down microsecond in the new unit
00168  */
00169 double nl_cancel_down_us(uint32_t l, char **unit)
00170 {
00171         if (l >= 1000000) {
00172                 *unit = "s";
00173                 return ((double) l) / 1000000;
00174         } else if (l >= 1000) {
00175                 *unit = "ms";
00176                 return ((double) l) / 1000;
00177         } else {
00178                 *unit = "us";
00179                 return (double) l;
00180         }
00181 }
00182 
00183 /** @} */
00184 
00185 /**
00186  * @name Generic Unit Translations
00187  * @{
00188  */
00189 
00190 /**
00191  * Convert a character string to a size
00192  * @arg str             size encoded as character string
00193  *
00194  * Converts the specified size as character to the corresponding
00195  * number of bytes.
00196  *
00197  * Supported formats are:
00198  *  - b,kb/k,m/mb,gb/g for bytes
00199  *  - bit,kbit/mbit/gbit
00200  *
00201  * @return The number of bytes or -1 if the string is unparseable
00202  */
00203 long nl_size2int(const char *str)
00204 {
00205         char *p;
00206         long l = strtol(str, &p, 0);
00207         if (p == str)
00208                 return -1;
00209 
00210         if (*p) {
00211                 if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
00212                         l *= 1024;
00213                 else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
00214                         l *= 1024*1024*1024;
00215                 else if (!strcasecmp(p, "gbit"))
00216                         l *= 1024*1024*1024/8;
00217                 else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
00218                         l *= 1024*1024;
00219                 else if (!strcasecmp(p, "mbit"))
00220                         l *= 1024*1024/8;
00221                 else if (!strcasecmp(p, "kbit"))
00222                         l *= 1024/8;
00223                 else if (!strcasecmp(p, "bit"))
00224                         l /= 8;
00225                 else if (strcasecmp(p, "b") != 0)
00226                         return -1;
00227         }
00228 
00229         return l;
00230 }
00231 
00232 /**
00233  * Convert a character string to a probability
00234  * @arg str             probability encoded as character string
00235  *
00236  * Converts the specified probability as character to the
00237  * corresponding probability number.
00238  *
00239  * Supported formats are:
00240  *  - 0.0-1.0
00241  *  - 0%-100%
00242  *
00243  * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
00244  */
00245 long nl_prob2int(const char *str)
00246 {
00247         char *p;
00248         double d = strtod(str, &p);
00249 
00250         if (p == str)
00251                 return -1;
00252 
00253         if (d > 1.0)
00254                 d /= 100.0f;
00255 
00256         if (d > 1.0f || d < 0.0f)
00257                 return -1;
00258 
00259         if (*p && strcmp(p, "%") != 0)
00260                 return -1;
00261 
00262         return rint(d * NL_PROB_MAX);
00263 }
00264 
00265 /** @} */
00266 
00267 /**
00268  * @name Time Translations
00269  * @{
00270  */
00271 
00272 #ifdef USER_HZ
00273 static uint32_t user_hz = USER_HZ;
00274 #else
00275 static uint32_t user_hz = 100;
00276 #endif
00277 
00278 static double ticks_per_usec = 1.0f;
00279 
00280 /* Retrieves the configured HZ and ticks/us value in the kernel.
00281  * The value is cached. Supported ways of getting it:
00282  *
00283  * 1) environment variable
00284  * 2) /proc/net/psched and sysconf
00285  *
00286  * Supports the environment variables:
00287  *   PROC_NET_PSCHED  - may point to psched file in /proc
00288  *   PROC_ROOT        - may point to /proc fs */ 
00289 static void __init get_psched_settings(void)
00290 {
00291         char name[FILENAME_MAX];
00292         FILE *fd;
00293         int got_hz = 0, got_tick = 0;
00294 
00295         if (getenv("HZ")) {
00296                 long hz = strtol(getenv("HZ"), NULL, 0);
00297 
00298                 if (LONG_MIN != hz && LONG_MAX != hz) {
00299                         user_hz = hz;
00300                         got_hz = 1;
00301                 }
00302         }
00303 
00304         if (!got_hz)
00305                 user_hz = sysconf(_SC_CLK_TCK);
00306 
00307         if (getenv("TICKS_PER_USEC")) {
00308                 double t = strtod(getenv("TICKS_PER_USEC"), NULL);
00309 
00310                 ticks_per_usec = t;
00311                 got_tick = 1;
00312         }
00313                 
00314 
00315         if (getenv("PROC_NET_PSCHED"))
00316                 snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
00317         else if (getenv("PROC_ROOT"))
00318                 snprintf(name, sizeof(name), "%s/net/psched",
00319                          getenv("PROC_ROOT"));
00320         else
00321                 strncpy(name, "/proc/net/psched", sizeof(name) - 1);
00322 
00323         if ((fd = fopen(name, "r"))) {
00324                 uint32_t tick, us, nom;
00325                 int r = fscanf(fd, "%08x%08x%08x%*08x", &tick, &us, &nom);
00326 
00327                 if (4 == r && nom == 1000000 && !got_tick)
00328                         ticks_per_usec = (double)tick/(double)us;
00329                         
00330                 fclose(fd);
00331         }
00332 }
00333 
00334 
00335 /**
00336  * Return the value of HZ
00337  */
00338 int nl_get_hz(void)
00339 {
00340         return user_hz;
00341 }
00342 
00343 
00344 /**
00345  * Convert micro seconds to ticks
00346  * @arg us              micro seconds
00347  * @return number of ticks
00348  */
00349 uint32_t nl_us2ticks(uint32_t us)
00350 {
00351         return us * ticks_per_usec;
00352 }
00353 
00354 
00355 /**
00356  * Convert ticks to micro seconds
00357  * @arg ticks           number of ticks
00358  * @return microseconds
00359  */
00360 uint32_t nl_ticks2us(uint32_t ticks)
00361 {
00362         return ticks / ticks_per_usec;
00363 }
00364 
00365 long nl_time2int(const char *str)
00366 {
00367         char *p;
00368         long l = strtol(str, &p, 0);
00369         if (p == str)
00370                 return -1;
00371 
00372         if (*p) {
00373                 if (!strcasecmp(p, "min") == 0 || !strcasecmp(p, "m"))
00374                         l *= 60;
00375                 else if (!strcasecmp(p, "hour") || !strcasecmp(p, "h"))
00376                         l *= 60*60;
00377                 else if (!strcasecmp(p, "day") || !strcasecmp(p, "d"))
00378                         l *= 60*60*24;
00379                 else if (strcasecmp(p, "s") != 0)
00380                         return -1;
00381         }
00382 
00383         return l;
00384 }
00385 
00386 /**
00387  * Convert milliseconds to a character string
00388  * @arg msec            number of milliseconds
00389  * @arg buf             destination buffer
00390  * @arg len             buffer length
00391  *
00392  * Converts milliseconds to a character string split up in days, hours,
00393  * minutes, seconds, and milliseconds and stores it in the specified
00394  * destination buffer.
00395  *
00396  * @return The destination buffer.
00397  */
00398 char * nl_msec2str(uint64_t msec, char *buf, size_t len)
00399 {
00400         int i, split[5];
00401         char *units[] = {"d", "h", "m", "s", "msec"};
00402 
00403 #define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit
00404         _SPLIT(0, 86400000);    /* days */
00405         _SPLIT(1, 3600000);     /* hours */
00406         _SPLIT(2, 60000);       /* minutes */
00407         _SPLIT(3, 1000);        /* seconds */
00408 #undef  _SPLIT
00409         split[4] = msec;
00410 
00411         memset(buf, 0, len);
00412 
00413         for (i = 0; i < ARRAY_SIZE(split); i++) {
00414                 if (split[i] > 0) {
00415                         char t[64];
00416                         snprintf(t, sizeof(t), "%s%d%s",
00417                                  strlen(buf) ? " " : "", split[i], units[i]);
00418                         strncat(buf, t, len - strlen(buf) - 1);
00419                 }
00420         }
00421 
00422         return buf;
00423 }
00424 
00425 /** @} */
00426 
00427 /**
00428  * @name Link Layer Protocol Translations
00429  * @{
00430  */
00431 
00432 static struct trans_tbl llprotos[] = {
00433         {0, "generic"},
00434         __ADD(ARPHRD_ETHER,ether)
00435         __ADD(ARPHRD_EETHER,eether)
00436         __ADD(ARPHRD_AX25,ax25)
00437         __ADD(ARPHRD_PRONET,pronet)
00438         __ADD(ARPHRD_CHAOS,chaos)
00439         __ADD(ARPHRD_IEEE802,ieee802)
00440         __ADD(ARPHRD_ARCNET,arcnet)
00441         __ADD(ARPHRD_APPLETLK,atalk)
00442         __ADD(ARPHRD_DLCI,dlci)
00443         __ADD(ARPHRD_ATM,atm)
00444         __ADD(ARPHRD_METRICOM,metricom)
00445         __ADD(ARPHRD_IEEE1394,ieee1394)
00446 #ifdef ARPHRD_EUI64
00447         __ADD(ARPHRD_EUI64,eui64)
00448 #endif
00449         __ADD(ARPHRD_INFINIBAND,infiniband)
00450         __ADD(ARPHRD_SLIP,slip)
00451         __ADD(ARPHRD_CSLIP,cslip)
00452         __ADD(ARPHRD_SLIP6,slip6)
00453         __ADD(ARPHRD_CSLIP6,cslip6)
00454         __ADD(ARPHRD_RSRVD,rsrvd)
00455         __ADD(ARPHRD_ADAPT,adapt)
00456         __ADD(ARPHRD_ROSE,rose)
00457         __ADD(ARPHRD_X25,x25)
00458 #ifdef ARPHRD_HWX25
00459         __ADD(ARPHRD_HWX25,hwx25)
00460 #endif
00461         __ADD(ARPHRD_PPP,ppp)
00462         __ADD(ARPHRD_HDLC,hdlc)
00463         __ADD(ARPHRD_LAPB,lapb)
00464         __ADD(ARPHRD_DDCMP,ddcmp)
00465         __ADD(ARPHRD_RAWHDLC,rawhdlc)
00466         __ADD(ARPHRD_TUNNEL,ipip)
00467         __ADD(ARPHRD_TUNNEL6,tunnel6)
00468         __ADD(ARPHRD_FRAD,frad)
00469         __ADD(ARPHRD_SKIP,skip)
00470         __ADD(ARPHRD_LOOPBACK,loopback)
00471         __ADD(ARPHRD_LOCALTLK,localtlk)
00472         __ADD(ARPHRD_FDDI,fddi)
00473         __ADD(ARPHRD_BIF,bif)
00474         __ADD(ARPHRD_SIT,sit)
00475         __ADD(ARPHRD_IPDDP,ip/ddp)
00476         __ADD(ARPHRD_IPGRE,gre)
00477         __ADD(ARPHRD_PIMREG,pimreg)
00478         __ADD(ARPHRD_HIPPI,hippi)
00479         __ADD(ARPHRD_ASH,ash)
00480         __ADD(ARPHRD_ECONET,econet)
00481         __ADD(ARPHRD_IRDA,irda)
00482         __ADD(ARPHRD_FCPP,fcpp)
00483         __ADD(ARPHRD_FCAL,fcal)
00484         __ADD(ARPHRD_FCPL,fcpl)
00485         __ADD(ARPHRD_FCFABRIC,fcfb_0)
00486         __ADD(ARPHRD_FCFABRIC+1,fcfb_1)
00487         __ADD(ARPHRD_FCFABRIC+2,fcfb_2)
00488         __ADD(ARPHRD_FCFABRIC+3,fcfb_3)
00489         __ADD(ARPHRD_FCFABRIC+4,fcfb_4)
00490         __ADD(ARPHRD_FCFABRIC+5,fcfb_5)
00491         __ADD(ARPHRD_FCFABRIC+6,fcfb_6)
00492         __ADD(ARPHRD_FCFABRIC+7,fcfb_7)
00493         __ADD(ARPHRD_FCFABRIC+8,fcfb_8)
00494         __ADD(ARPHRD_FCFABRIC+9,fcfb_9)
00495         __ADD(ARPHRD_FCFABRIC+10,fcfb_10)
00496         __ADD(ARPHRD_FCFABRIC+11,fcfb_11)
00497         __ADD(ARPHRD_FCFABRIC+12,fcfb_12)
00498         __ADD(ARPHRD_IEEE802_TR,tr)
00499         __ADD(ARPHRD_IEEE80211,ieee802.11)
00500 #ifdef ARPHRD_IEEE80211_PRISM
00501         __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
00502 #endif
00503 #ifdef ARPHRD_VOID
00504         __ADD(ARPHRD_VOID,void)
00505 #endif
00506 };
00507 
00508 /**
00509  * Convert a link layer protocol to a character string (Reentrant).
00510  * @arg llproto         link layer protocol
00511  * @arg buf             destination buffer
00512  * @arg len             buffer length
00513  *
00514  * Converts a link layer protocol to a character string and stores
00515  * it in the specified destination buffer.
00516  *
00517  * @return The destination buffer or the type encoded in hexidecimal
00518  *         form if no match was found.
00519  */
00520 char * nl_llproto2str(int llproto, char *buf, size_t len)
00521 {
00522         return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
00523 }
00524 
00525 /**
00526  * Convert a character string to a link layer protocol
00527  * @arg name            name of link layer protocol
00528  *
00529  * Converts the provided character string specifying a link layer
00530  * protocl to the corresponding numeric value.
00531  *
00532  * @return link layer protocol or a negative value if none was found.
00533  */
00534 int nl_str2llproto(const char *name)
00535 {
00536         return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
00537 }
00538 
00539 /** @} */
00540 
00541 
00542 /**
00543  * @name Ethernet Protocol Translations
00544  * @{
00545  */
00546 
00547 static struct trans_tbl ether_protos[] = {
00548         __ADD(ETH_P_LOOP,loop)
00549         __ADD(ETH_P_PUP,pup)
00550         __ADD(ETH_P_PUPAT,pupat)
00551         __ADD(ETH_P_IP,ip)
00552         __ADD(ETH_P_X25,x25)
00553         __ADD(ETH_P_ARP,arp)
00554         __ADD(ETH_P_BPQ,bpq)
00555         __ADD(ETH_P_IEEEPUP,ieeepup)
00556         __ADD(ETH_P_IEEEPUPAT,ieeepupat)
00557         __ADD(ETH_P_DEC,dec)
00558         __ADD(ETH_P_DNA_DL,dna_dl)
00559         __ADD(ETH_P_DNA_RC,dna_rc)
00560         __ADD(ETH_P_DNA_RT,dna_rt)
00561         __ADD(ETH_P_LAT,lat)
00562         __ADD(ETH_P_DIAG,diag)
00563         __ADD(ETH_P_CUST,cust)
00564         __ADD(ETH_P_SCA,sca)
00565         __ADD(ETH_P_RARP,rarp)
00566         __ADD(ETH_P_ATALK,atalk)
00567         __ADD(ETH_P_AARP,aarp)
00568 #ifdef ETH_P_8021Q
00569         __ADD(ETH_P_8021Q,802.1q)
00570 #endif
00571         __ADD(ETH_P_IPX,ipx)
00572         __ADD(ETH_P_IPV6,ipv6)
00573 #ifdef ETH_P_WCCP
00574         __ADD(ETH_P_WCCP,wccp)
00575 #endif
00576         __ADD(ETH_P_PPP_DISC,ppp_disc)
00577         __ADD(ETH_P_PPP_SES,ppp_ses)
00578         __ADD(ETH_P_MPLS_UC,mpls_uc)
00579         __ADD(ETH_P_MPLS_MC,mpls_mc)
00580         __ADD(ETH_P_ATMMPOA,atmmpoa)
00581         __ADD(ETH_P_ATMFATE,atmfate)
00582         __ADD(ETH_P_EDP2,edp2)
00583         __ADD(ETH_P_802_3,802.3)
00584         __ADD(ETH_P_AX25,ax25)
00585         __ADD(ETH_P_ALL,all)
00586         __ADD(ETH_P_802_2,802.2)
00587         __ADD(ETH_P_SNAP,snap)
00588         __ADD(ETH_P_DDCMP,ddcmp)
00589         __ADD(ETH_P_WAN_PPP,wan_ppp)
00590         __ADD(ETH_P_PPP_MP,ppp_mp)
00591         __ADD(ETH_P_LOCALTALK,localtalk)
00592         __ADD(ETH_P_PPPTALK,ppptalk)
00593         __ADD(ETH_P_TR_802_2,tr_802.2)
00594         __ADD(ETH_P_MOBITEX,mobitex)
00595         __ADD(ETH_P_CONTROL,control)
00596         __ADD(ETH_P_IRDA,irda)
00597         __ADD(ETH_P_ECONET,econet)
00598         __ADD(ETH_P_HDLC,hdlc)
00599 };
00600 
00601 /**
00602  * Convert a ethernet protocol to a character string (Reentrant).
00603  * @arg eproto          ethernet protocol
00604  * @arg buf             destination buffer
00605  * @arg len             buffer length
00606  *
00607  * Converts a ethernet protocol to a character string and stores
00608  * it in the specified destination buffer.
00609  *
00610  * @return The destination buffer or the type encoded in hexidecimal
00611  *         form if no match was found.
00612  */
00613 char *nl_ether_proto2str(int eproto, char *buf, size_t len)
00614 {
00615         return __type2str(eproto, buf, len, ether_protos,
00616                             ARRAY_SIZE(ether_protos));
00617 }
00618 
00619 /**
00620  * Convert a character string to a ethernet protocol
00621  * @arg name            name of ethernet protocol
00622  *
00623  * Converts the provided character string specifying a ethernet
00624  * protocl to the corresponding numeric value.
00625  *
00626  * @return ethernet protocol or a negative value if none was found.
00627  */
00628 int nl_str2ether_proto(const char *name)
00629 {
00630         return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
00631 }
00632 
00633 /** @} */
00634 
00635 /** @} */

Generated on Fri Apr 27 14:14:07 2007 for libnl by  doxygen 1.5.1