Commit 32ccd2b6 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] seq_path(), /proc/mounts and /proc/swaps

This adds a new seq_...() helper:

   seq_path(seq_file, mnt, dentry, escape)

It spits the pathname into seq_file, does octal escapes for given set of
characters, returns the number of characters it'd produced or -1 in case
of error.  Long names are handled gracefully - you don't need anything
to do, generic seq_file logics will do the right thing.

/proc/mounts and /proc/swaps are converted to use of seq_path(), some
junk removed.

/proc/pid/maps will be converted next.
parent ecdb3063
...@@ -1275,7 +1275,7 @@ void d_move(struct dentry * dentry, struct dentry * target) ...@@ -1275,7 +1275,7 @@ void d_move(struct dentry * dentry, struct dentry * target)
* the string " (deleted)" is appended. Note that this is ambiguous. Returns * the string " (deleted)" is appended. Note that this is ambiguous. Returns
* the buffer. * the buffer.
* *
* "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock. * "buflen" should be positive. Caller holds the dcache_lock.
*/ */
static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt, struct dentry *root, struct vfsmount *rootmnt,
...@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ...@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
if (!IS_ROOT(dentry) && d_unhashed(dentry)) { if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
buflen -= 10; buflen -= 10;
end -= 10; end -= 10;
if (buflen < 0)
goto Elong;
memcpy(end, " (deleted)", 10); memcpy(end, " (deleted)", 10);
} }
if (buflen < 1)
goto Elong;
/* Get '/' right */ /* Get '/' right */
retval = end-1; retval = end-1;
*retval = '/'; *retval = '/';
...@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ...@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
buflen -= namelen + 1; buflen -= namelen + 1;
if (buflen < 0) if (buflen < 0)
return ERR_PTR(-ENAMETOOLONG); goto Elong;
end -= namelen; end -= namelen;
memcpy(end, dentry->d_name.name, namelen); memcpy(end, dentry->d_name.name, namelen);
*--end = '/'; *--end = '/';
...@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ...@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
global_root: global_root:
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
buflen -= namelen; buflen -= namelen;
if (buflen >= 0) { if (buflen < 0)
goto Elong;
retval -= namelen-1; /* hit the slash */ retval -= namelen-1; /* hit the slash */
memcpy(retval, dentry->d_name.name, namelen); memcpy(retval, dentry->d_name.name, namelen);
} else
retval = ERR_PTR(-ENAMETOOLONG);
return retval; return retval;
Elong:
return ERR_PTR(-ENAMETOOLONG);
} }
/* write full pathname into buffer and return start of pathname */ /* write full pathname into buffer and return start of pathname */
......
...@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v) ...@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v)
{ 0, NULL } { 0, NULL }
}; };
struct proc_fs_info *fs_infop; struct proc_fs_info *fs_infop;
char *path_buf, *path;
path_buf = (char *) __get_free_page(GFP_KERNEL);
if (!path_buf)
return -ENOMEM;
path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE);
if (IS_ERR(path))
path = " (too long)";
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
seq_putc(m, ' '); seq_putc(m, ' ');
mangle(m, path); seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
free_page((unsigned long) path_buf);
seq_putc(m, ' '); seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name); mangle(m, mnt->mnt_sb->s_type->name);
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
......
...@@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...) ...@@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...)
return -1; return -1;
} }
int seq_path(struct seq_file *m,
struct vfsmount *mnt, struct dentry *dentry,
char *esc)
{
if (m->count < m->size) {
char *s = m->buf + m->count;
char *p = d_path(dentry, mnt, s, m->size - m->count);
if (!IS_ERR(p)) {
while (s <= p) {
char c = *p++;
if (!c) {
p = m->buf + m->count;
m->count = s - m->buf;
return s - p;
} else if (!strchr(esc, c)) {
*s++ = c;
} else if (s + 4 > p) {
break;
} else {
*s++ = '\\';
*s++ = '0' + ((c & 0300) >> 6);
*s++ = '0' + ((c & 070) >> 3);
*s++ = '0' + (c & 07);
}
}
}
}
m->count = m->size;
return -1;
}
static void *single_start(struct seq_file *p, loff_t *pos) static void *single_start(struct seq_file *p, loff_t *pos)
{ {
return NULL + (*pos == 0); return NULL + (*pos == 0);
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
struct seq_operations; struct seq_operations;
struct file; struct file;
struct vfsmount;
struct dentry;
struct inode; struct inode;
struct seq_file { struct seq_file {
...@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s) ...@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s)
int seq_printf(struct seq_file *, const char *, ...) int seq_printf(struct seq_file *, const char *, ...)
__attribute__ ((format (printf,2,3))); __attribute__ ((format (printf,2,3)));
int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);
int single_open(struct file *, int (*)(struct seq_file *, void *), void *); int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct file *); int single_release(struct inode *, struct file *);
int seq_release_private(struct inode *, struct file *); int seq_release_private(struct inode *, struct file *);
......
...@@ -1118,14 +1118,9 @@ static void *swap_start(struct seq_file *swap, loff_t *pos) ...@@ -1118,14 +1118,9 @@ static void *swap_start(struct seq_file *swap, loff_t *pos)
struct swap_info_struct *ptr = swap_info; struct swap_info_struct *ptr = swap_info;
int i; int i;
loff_t l = *pos; loff_t l = *pos;
char * page = (char *) __get_free_page(GFP_KERNEL);
swap->private = page; /* save for swap_show */
swap_list_lock(); swap_list_lock();
if (!page)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_swapfiles; i++, ptr++) { for (i = 0; i < nr_swapfiles; i++, ptr++) {
if (!(ptr->flags & SWP_USED) || !ptr->swap_map) if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
continue; continue;
...@@ -1154,24 +1149,21 @@ static void *swap_next(struct seq_file *swap, void *v, loff_t *pos) ...@@ -1154,24 +1149,21 @@ static void *swap_next(struct seq_file *swap, void *v, loff_t *pos)
static void swap_stop(struct seq_file *swap, void *v) static void swap_stop(struct seq_file *swap, void *v)
{ {
swap_list_unlock(); swap_list_unlock();
free_page((unsigned long) swap->private);
swap->private = NULL;
} }
static int swap_show(struct seq_file *swap, void *v) static int swap_show(struct seq_file *swap, void *v)
{ {
struct swap_info_struct *ptr = v; struct swap_info_struct *ptr = v;
struct file *file; struct file *file;
char *path; int len;
if (v == swap_info) if (v == swap_info)
seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
file = ptr->swap_file; file = ptr->swap_file;
path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE); len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n", len < 40 ? 40 - len : 1, " ",
path,
S_ISBLK(file->f_dentry->d_inode->i_mode) ? S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t", "partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10), ptr->pages << (PAGE_SHIFT - 10),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment