diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-03 12:00:44 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-04 00:13:11 -0400 |
commit | 4b6ccca701ef5977d0ffbc2c932430dea88b38b6 (patch) | |
tree | f8daa1243e24168fba2595c29805765856708673 /lib/vsprintf.c | |
parent | cffe78d92c217a57f57ec6743f71adfe39ea543e (diff) |
add formats for dentry/file pathnames
New formats: %p[dD][234]?. The next pointer is interpreted as struct dentry *
or struct file * resp. ('d' => dentry, 'D' => file) and the last component(s)
of pathname are printed (%pd => just the last one, %pd2 => the last two, etc.)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 739a36366b79..26559bdb4c49 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/math64.h> | 26 | #include <linux/math64.h> |
27 | #include <linux/uaccess.h> | 27 | #include <linux/uaccess.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/dcache.h> | ||
29 | #include <net/addrconf.h> | 30 | #include <net/addrconf.h> |
30 | 31 | ||
31 | #include <asm/page.h> /* for PAGE_SIZE */ | 32 | #include <asm/page.h> /* for PAGE_SIZE */ |
@@ -532,6 +533,81 @@ char *string(char *buf, char *end, const char *s, struct printf_spec spec) | |||
532 | return buf; | 533 | return buf; |
533 | } | 534 | } |
534 | 535 | ||
536 | static void widen(char *buf, char *end, unsigned len, unsigned spaces) | ||
537 | { | ||
538 | size_t size; | ||
539 | if (buf >= end) /* nowhere to put anything */ | ||
540 | return; | ||
541 | size = end - buf; | ||
542 | if (size <= spaces) { | ||
543 | memset(buf, ' ', size); | ||
544 | return; | ||
545 | } | ||
546 | if (len) { | ||
547 | if (len > size - spaces) | ||
548 | len = size - spaces; | ||
549 | memmove(buf + spaces, buf, len); | ||
550 | } | ||
551 | memset(buf, ' ', spaces); | ||
552 | } | ||
553 | |||
554 | static noinline_for_stack | ||
555 | char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec, | ||
556 | const char *fmt) | ||
557 | { | ||
558 | const char *array[4], *s; | ||
559 | const struct dentry *p; | ||
560 | int depth; | ||
561 | int i, n; | ||
562 | |||
563 | switch (fmt[1]) { | ||
564 | case '2': case '3': case '4': | ||
565 | depth = fmt[1] - '0'; | ||
566 | break; | ||
567 | default: | ||
568 | depth = 1; | ||
569 | } | ||
570 | |||
571 | rcu_read_lock(); | ||
572 | for (i = 0; i < depth; i++, d = p) { | ||
573 | p = ACCESS_ONCE(d->d_parent); | ||
574 | array[i] = ACCESS_ONCE(d->d_name.name); | ||
575 | if (p == d) { | ||
576 | if (i) | ||
577 | array[i] = ""; | ||
578 | i++; | ||
579 | break; | ||
580 | } | ||
581 | } | ||
582 | s = array[--i]; | ||
583 | for (n = 0; n != spec.precision; n++, buf++) { | ||
584 | char c = *s++; | ||
585 | if (!c) { | ||
586 | if (!i) | ||
587 | break; | ||
588 | c = '/'; | ||
589 | s = array[--i]; | ||
590 | } | ||
591 | if (buf < end) | ||
592 | *buf = c; | ||
593 | } | ||
594 | rcu_read_unlock(); | ||
595 | if (n < spec.field_width) { | ||
596 | /* we want to pad the sucker */ | ||
597 | unsigned spaces = spec.field_width - n; | ||
598 | if (!(spec.flags & LEFT)) { | ||
599 | widen(buf - n, end, n, spaces); | ||
600 | return buf + spaces; | ||
601 | } | ||
602 | while (spaces--) { | ||
603 | if (buf < end) | ||
604 | *buf = ' '; | ||
605 | ++buf; | ||
606 | } | ||
607 | } | ||
608 | return buf; | ||
609 | } | ||
610 | |||
535 | static noinline_for_stack | 611 | static noinline_for_stack |
536 | char *symbol_string(char *buf, char *end, void *ptr, | 612 | char *symbol_string(char *buf, char *end, void *ptr, |
537 | struct printf_spec spec, const char *fmt) | 613 | struct printf_spec spec, const char *fmt) |
@@ -1253,6 +1329,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
1253 | spec.base = 16; | 1329 | spec.base = 16; |
1254 | return number(buf, end, | 1330 | return number(buf, end, |
1255 | (unsigned long long) *((phys_addr_t *)ptr), spec); | 1331 | (unsigned long long) *((phys_addr_t *)ptr), spec); |
1332 | case 'd': | ||
1333 | return dentry_name(buf, end, ptr, spec, fmt); | ||
1334 | case 'D': | ||
1335 | return dentry_name(buf, end, | ||
1336 | ((const struct file *)ptr)->f_path.dentry, | ||
1337 | spec, fmt); | ||
1256 | } | 1338 | } |
1257 | spec.flags |= SMALL; | 1339 | spec.flags |= SMALL; |
1258 | if (spec.field_width == -1) { | 1340 | if (spec.field_width == -1) { |