aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/vsprintf.c124
1 files changed, 122 insertions, 2 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 7d8467645d2e..739a36366b79 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -923,6 +923,103 @@ char *ip4_addr_string(char *buf, char *end, const u8 *addr,
923} 923}
924 924
925static noinline_for_stack 925static noinline_for_stack
926char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa,
927 struct printf_spec spec, const char *fmt)
928{
929 bool have_p = false, have_s = false, have_f = false, have_c = false;
930 char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") +
931 sizeof(":12345") + sizeof("/123456789") +
932 sizeof("%1234567890")];
933 char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr);
934 const u8 *addr = (const u8 *) &sa->sin6_addr;
935 char fmt6[2] = { fmt[0], '6' };
936 u8 off = 0;
937
938 fmt++;
939 while (isalpha(*++fmt)) {
940 switch (*fmt) {
941 case 'p':
942 have_p = true;
943 break;
944 case 'f':
945 have_f = true;
946 break;
947 case 's':
948 have_s = true;
949 break;
950 case 'c':
951 have_c = true;
952 break;
953 }
954 }
955
956 if (have_p || have_s || have_f) {
957 *p = '[';
958 off = 1;
959 }
960
961 if (fmt6[0] == 'I' && have_c)
962 p = ip6_compressed_string(ip6_addr + off, addr);
963 else
964 p = ip6_string(ip6_addr + off, addr, fmt6);
965
966 if (have_p || have_s || have_f)
967 *p++ = ']';
968
969 if (have_p) {
970 *p++ = ':';
971 p = number(p, pend, ntohs(sa->sin6_port), spec);
972 }
973 if (have_f) {
974 *p++ = '/';
975 p = number(p, pend, ntohl(sa->sin6_flowinfo &
976 IPV6_FLOWINFO_MASK), spec);
977 }
978 if (have_s) {
979 *p++ = '%';
980 p = number(p, pend, sa->sin6_scope_id, spec);
981 }
982 *p = '\0';
983
984 return string(buf, end, ip6_addr, spec);
985}
986
987static noinline_for_stack
988char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
989 struct printf_spec spec, const char *fmt)
990{
991 bool have_p = false;
992 char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")];
993 char *pend = ip4_addr + sizeof(ip4_addr);
994 const u8 *addr = (const u8 *) &sa->sin_addr.s_addr;
995 char fmt4[3] = { fmt[0], '4', 0 };
996
997 fmt++;
998 while (isalpha(*++fmt)) {
999 switch (*fmt) {
1000 case 'p':
1001 have_p = true;
1002 break;
1003 case 'h':
1004 case 'l':
1005 case 'n':
1006 case 'b':
1007 fmt4[2] = *fmt;
1008 break;
1009 }
1010 }
1011
1012 p = ip4_string(ip4_addr, addr, fmt4);
1013 if (have_p) {
1014 *p++ = ':';
1015 p = number(p, pend, ntohs(sa->sin_port), spec);
1016 }
1017 *p = '\0';
1018
1019 return string(buf, end, ip4_addr, spec);
1020}
1021
1022static noinline_for_stack
926char *uuid_string(char *buf, char *end, const u8 *addr, 1023char *uuid_string(char *buf, char *end, const u8 *addr,
927 struct printf_spec spec, const char *fmt) 1024 struct printf_spec spec, const char *fmt)
928{ 1025{
@@ -1007,11 +1104,17 @@ int kptr_restrict __read_mostly;
1007 * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way 1104 * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
1008 * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) 1105 * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
1009 * IPv6 uses colon separated network-order 16 bit hex with leading 0's 1106 * IPv6 uses colon separated network-order 16 bit hex with leading 0's
1107 * [S][pfs]
1108 * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
1109 * [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
1010 * - 'i' [46] for 'raw' IPv4/IPv6 addresses 1110 * - 'i' [46] for 'raw' IPv4/IPv6 addresses
1011 * IPv6 omits the colons (01020304...0f) 1111 * IPv6 omits the colons (01020304...0f)
1012 * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) 1112 * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
1013 * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order 1113 * [S][pfs]
1014 * - 'I6c' for IPv6 addresses printed as specified by 1114 * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
1115 * [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
1116 * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
1117 * - 'I[6S]c' for IPv6 addresses printed as specified by
1015 * http://tools.ietf.org/html/rfc5952 1118 * http://tools.ietf.org/html/rfc5952
1016 * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form 1119 * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
1017 * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 1120 * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
@@ -1093,6 +1196,21 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
1093 return ip6_addr_string(buf, end, ptr, spec, fmt); 1196 return ip6_addr_string(buf, end, ptr, spec, fmt);
1094 case '4': 1197 case '4':
1095 return ip4_addr_string(buf, end, ptr, spec, fmt); 1198 return ip4_addr_string(buf, end, ptr, spec, fmt);
1199 case 'S': {
1200 const union {
1201 struct sockaddr raw;
1202 struct sockaddr_in v4;
1203 struct sockaddr_in6 v6;
1204 } *sa = ptr;
1205
1206 switch (sa->raw.sa_family) {
1207 case AF_INET:
1208 return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt);
1209 case AF_INET6:
1210 return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt);
1211 default:
1212 return string(buf, end, "(invalid address)", spec);
1213 }}
1096 } 1214 }
1097 break; 1215 break;
1098 case 'U': 1216 case 'U':
@@ -1370,6 +1488,8 @@ qualifier:
1370 * %pI6 print an IPv6 address with colons 1488 * %pI6 print an IPv6 address with colons
1371 * %pi6 print an IPv6 address without colons 1489 * %pi6 print an IPv6 address without colons
1372 * %pI6c print an IPv6 address as specified by RFC 5952 1490 * %pI6c print an IPv6 address as specified by RFC 5952
1491 * %pIS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
1492 * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
1373 * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper 1493 * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
1374 * case. 1494 * case.
1375 * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 1495 * %*ph[CDN] a variable-length hex string with a separator (supports up to 64