radix_tree_tag_get() is not as safe as the docs make out [ver #2]
[safe/jmp/linux-2.6] / lib / vsprintf.c
index 3b8aeec..24112e5 100644 (file)
@@ -381,8 +381,8 @@ static noinline char *put_dec(char *buf, unsigned long long num)
 #define PLUS   4               /* show plus */
 #define SPACE  8               /* space if plus */
 #define LEFT   16              /* left justified */
-#define SMALL  32              /* Must be 32 == 0x20 */
-#define SPECIAL        64              /* 0x */
+#define SMALL  32              /* use lowercase in hex (must be 32 == 0x20) */
+#define SPECIAL        64              /* prefix hex with "0x", octal with "0" */
 
 enum format_type {
        FORMAT_TYPE_NONE, /* Just a string part */
@@ -408,12 +408,12 @@ enum format_type {
 };
 
 struct printf_spec {
-       enum format_type        type;
-       int                     flags;          /* flags to number() */
-       int                     field_width;    /* width of output field */
-       int                     base;
-       int                     precision;      /* # of digits/chars */
-       int                     qualifier;
+       u16     type;
+       s16     field_width;    /* width of output field */
+       u8      flags;          /* flags to number() */
+       u8      base;
+       s8      precision;      /* # of digits/chars */
+       u8      qualifier;
 };
 
 static char *number(char *buf, char *end, unsigned long long num,
@@ -597,22 +597,35 @@ static char *resource_string(char *buf, char *end, struct resource *res,
 #ifndef MEM_RSRC_PRINTK_SIZE
 #define MEM_RSRC_PRINTK_SIZE   10
 #endif
-       struct printf_spec hex_spec = {
+       static const struct printf_spec io_spec = {
                .base = 16,
+               .field_width = IO_RSRC_PRINTK_SIZE,
                .precision = -1,
                .flags = SPECIAL | SMALL | ZEROPAD,
        };
-       struct printf_spec dec_spec = {
+       static const struct printf_spec mem_spec = {
+               .base = 16,
+               .field_width = MEM_RSRC_PRINTK_SIZE,
+               .precision = -1,
+               .flags = SPECIAL | SMALL | ZEROPAD,
+       };
+       static const struct printf_spec bus_spec = {
+               .base = 16,
+               .field_width = 2,
+               .precision = -1,
+               .flags = SMALL | ZEROPAD,
+       };
+       static const struct printf_spec dec_spec = {
                .base = 10,
                .precision = -1,
                .flags = 0,
        };
-       struct printf_spec str_spec = {
+       static const struct printf_spec str_spec = {
                .field_width = -1,
                .precision = 10,
                .flags = LEFT,
        };
-       struct printf_spec flag_spec = {
+       static const struct printf_spec flag_spec = {
                .base = 16,
                .precision = -1,
                .flags = SPECIAL | SMALL,
@@ -622,47 +635,48 @@ static char *resource_string(char *buf, char *end, struct resource *res,
         * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */
 #define RSRC_BUF_SIZE          ((2 * sizeof(resource_size_t)) + 4)
 #define FLAG_BUF_SIZE          (2 * sizeof(res->flags))
-#define DECODED_BUF_SIZE       sizeof("[mem - 64bit pref disabled]")
+#define DECODED_BUF_SIZE       sizeof("[mem - 64bit pref window disabled]")
 #define RAW_BUF_SIZE           sizeof("[mem - flags 0x]")
        char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
                     2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)];
 
        char *p = sym, *pend = sym + sizeof(sym);
-       int size = -1, addr = 0;
        int decode = (fmt[0] == 'R') ? 1 : 0;
-
-       if (res->flags & IORESOURCE_IO) {
-               size = IO_RSRC_PRINTK_SIZE;
-               addr = 1;
-       } else if (res->flags & IORESOURCE_MEM) {
-               size = MEM_RSRC_PRINTK_SIZE;
-               addr = 1;
-       }
+       const struct printf_spec *specp;
 
        *p++ = '[';
-       if (res->flags & IORESOURCE_IO)
+       if (res->flags & IORESOURCE_IO) {
                p = string(p, pend, "io  ", str_spec);
-       else if (res->flags & IORESOURCE_MEM)
+               specp = &io_spec;
+       } else if (res->flags & IORESOURCE_MEM) {
                p = string(p, pend, "mem ", str_spec);
-       else if (res->flags & IORESOURCE_IRQ)
+               specp = &mem_spec;
+       } else if (res->flags & IORESOURCE_IRQ) {
                p = string(p, pend, "irq ", str_spec);
-       else if (res->flags & IORESOURCE_DMA)
+               specp = &dec_spec;
+       } else if (res->flags & IORESOURCE_DMA) {
                p = string(p, pend, "dma ", str_spec);
-       else {
+               specp = &dec_spec;
+       } else if (res->flags & IORESOURCE_BUS) {
+               p = string(p, pend, "bus ", str_spec);
+               specp = &bus_spec;
+       } else {
                p = string(p, pend, "??? ", str_spec);
+               specp = &mem_spec;
                decode = 0;
        }
-       hex_spec.field_width = size;
-       p = number(p, pend, res->start, addr ? hex_spec : dec_spec);
+       p = number(p, pend, res->start, *specp);
        if (res->start != res->end) {
                *p++ = '-';
-               p = number(p, pend, res->end, addr ? hex_spec : dec_spec);
+               p = number(p, pend, res->end, *specp);
        }
        if (decode) {
                if (res->flags & IORESOURCE_MEM_64)
                        p = string(p, pend, " 64bit", str_spec);
                if (res->flags & IORESOURCE_PREFETCH)
                        p = string(p, pend, " pref", str_spec);
+               if (res->flags & IORESOURCE_WINDOW)
+                       p = string(p, pend, " window", str_spec);
                if (res->flags & IORESOURCE_DISABLED)
                        p = string(p, pend, " disabled", str_spec);
        } else {
@@ -681,24 +695,55 @@ static char *mac_address_string(char *buf, char *end, u8 *addr,
        char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
        char *p = mac_addr;
        int i;
+       char separator;
+
+       if (fmt[1] == 'F') {            /* FDDI canonical format */
+               separator = '-';
+       } else {
+               separator = ':';
+       }
 
        for (i = 0; i < 6; i++) {
                p = pack_hex_byte(p, addr[i]);
                if (fmt[0] == 'M' && i != 5)
-                       *p++ = ':';
+                       *p++ = separator;
        }
        *p = '\0';
 
        return string(buf, end, mac_addr, spec);
 }
 
-static char *ip4_string(char *p, const u8 *addr, bool leading_zeros)
+static char *ip4_string(char *p, const u8 *addr, const char *fmt)
 {
        int i;
-
+       bool leading_zeros = (fmt[0] == 'i');
+       int index;
+       int step;
+
+       switch (fmt[2]) {
+       case 'h':
+#ifdef __BIG_ENDIAN
+               index = 0;
+               step = 1;
+#else
+               index = 3;
+               step = -1;
+#endif
+               break;
+       case 'l':
+               index = 3;
+               step = -1;
+               break;
+       case 'n':
+       case 'b':
+       default:
+               index = 0;
+               step = 1;
+               break;
+       }
        for (i = 0; i < 4; i++) {
                char temp[3];   /* hold each IP quad in reverse order */
-               int digits = put_dec_trunc(temp, addr[i]) - temp;
+               int digits = put_dec_trunc(temp, addr[index]) - temp;
                if (leading_zeros) {
                        if (digits < 3)
                                *p++ = '0';
@@ -710,6 +755,7 @@ static char *ip4_string(char *p, const u8 *addr, bool leading_zeros)
                        *p++ = temp[digits];
                if (i < 3)
                        *p++ = '.';
+               index += step;
        }
        *p = '\0';
 
@@ -789,7 +835,7 @@ static char *ip6_compressed_string(char *p, const char *addr)
        if (useIPv4) {
                if (needcolon)
                        *p++ = ':';
-               p = ip4_string(p, &in6.s6_addr[12], false);
+               p = ip4_string(p, &in6.s6_addr[12], "I4");
        }
        *p = '\0';
 
@@ -829,7 +875,7 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
 {
        char ip4_addr[sizeof("255.255.255.255")];
 
-       ip4_string(ip4_addr, addr, fmt[0] == 'i');
+       ip4_string(ip4_addr, addr, fmt);
 
        return string(buf, end, ip4_addr, spec);
 }
@@ -896,12 +942,15 @@ static char *uuid_string(char *buf, char *end, const u8 *addr,
  * - 'M' For a 6-byte MAC address, it prints the address in the
  *       usual colon-separated hex notation
  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
+ * - 'MF' For a 6-byte MAC FDDI address, it prints the address
+ *       with a dash-separated hex notation
  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
  *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
  *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
  * - 'i' [46] for 'raw' IPv4/IPv6 addresses
  *       IPv6 omits the colons (01020304...0f)
  *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
+ * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order
  * - 'I6c' for IPv6 addresses printed as specified by
  *       http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00
  * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
@@ -939,6 +988,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                return resource_string(buf, end, ptr, spec, fmt);
        case 'M':                       /* Colon separated: 00:01:02:03:04:05 */
        case 'm':                       /* Contiguous: 000102030405 */
+                                       /* [mM]F (FDDI, bit reversed) */
                return mac_address_string(buf, end, ptr, spec, fmt);
        case 'I':                       /* Formatted IP supported
                                         * 4:   1.2.3.4
@@ -1297,7 +1347,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                        break;
 
                case FORMAT_TYPE_NRCHARS: {
-                       int qualifier = spec.qualifier;
+                       u8 qualifier = spec.qualifier;
 
                        if (qualifier == 'l') {
                                long *ip = va_arg(args, long *);
@@ -1583,7 +1633,7 @@ do {                                                                      \
 
                case FORMAT_TYPE_NRCHARS: {
                        /* skip %n 's argument */
-                       int qualifier = spec.qualifier;
+                       u8 qualifier = spec.qualifier;
                        void *skip_arg;
                        if (qualifier == 'l')
                                skip_arg = va_arg(args, long *);
@@ -1849,7 +1899,9 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
        char *next;
        char digit;
        int num = 0;
-       int qualifier, base, field_width;
+       u8 qualifier;
+       u8 base;
+       s16 field_width;
        bool is_sign;
 
        while (*fmt && *str) {
@@ -1927,7 +1979,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
                {
                        char *s = (char *)va_arg(args, char *);
                        if (field_width == -1)
-                               field_width = INT_MAX;
+                               field_width = SHORT_MAX;
                        /* first, skip leading white space in buffer */
                        str = skip_spaces(str);