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)
* the string " (deleted)" is appended. Note that this is ambiguous. Returns
* 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,
struct dentry *root, struct vfsmount *rootmnt,
......@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
buflen -= 10;
end -= 10;
if (buflen < 0)
goto Elong;
memcpy(end, " (deleted)", 10);
}
if (buflen < 1)
goto Elong;
/* Get '/' right */
retval = end-1;
*retval = '/';
......@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
namelen = dentry->d_name.len;
buflen -= namelen + 1;
if (buflen < 0)
return ERR_PTR(-ENAMETOOLONG);
goto Elong;
end -= namelen;
memcpy(end, dentry->d_name.name, namelen);
*--end = '/';
......@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
global_root:
namelen = dentry->d_name.len;
buflen -= namelen;
if (buflen >= 0) {
retval -= namelen-1; /* hit the slash */
memcpy(retval, dentry->d_name.name, namelen);
} else
retval = ERR_PTR(-ENAMETOOLONG);
if (buflen < 0)
goto Elong;
retval -= namelen-1; /* hit the slash */
memcpy(retval, dentry->d_name.name, namelen);
return retval;
Elong:
return ERR_PTR(-ENAMETOOLONG);
}
/* write full pathname into buffer and return start of pathname */
......
......@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v)
{ 0, NULL }
};
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");
seq_putc(m, ' ');
mangle(m, path);
free_page((unsigned long) path_buf);
seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name);
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, ...)
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)
{
return NULL + (*pos == 0);
......
......@@ -8,6 +8,8 @@
struct seq_operations;
struct file;
struct vfsmount;
struct dentry;
struct inode;
struct seq_file {
......@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s)
int seq_printf(struct seq_file *, const char *, ...)
__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_release(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)
struct swap_info_struct *ptr = swap_info;
int i;
loff_t l = *pos;
char * page = (char *) __get_free_page(GFP_KERNEL);
swap->private = page; /* save for swap_show */
swap_list_lock();
if (!page)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_swapfiles; i++, ptr++) {
if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
continue;
......@@ -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)
{
swap_list_unlock();
free_page((unsigned long) swap->private);
swap->private = NULL;
}
static int swap_show(struct seq_file *swap, void *v)
{
struct swap_info_struct *ptr = v;
struct file *file;
char *path;
int len;
if (v == swap_info)
seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
file = ptr->swap_file;
path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE);
seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n",
path,
len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
len < 40 ? 40 - len : 1, " ",
S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t",
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