aboutsummaryrefslogtreecommitdiffstats
path: root/fs/seq_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/seq_file.c')
-rw-r--r--fs/seq_file.c113
1 files changed, 92 insertions, 21 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 853770274f20..3f54dbd6c49b 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -25,6 +25,7 @@
25 * into the buffer. In case of error ->start() and ->next() return 25 * into the buffer. In case of error ->start() and ->next() return
26 * ERR_PTR(error). In the end of sequence they return %NULL. ->show() 26 * ERR_PTR(error). In the end of sequence they return %NULL. ->show()
27 * returns 0 in case of success and negative number in case of error. 27 * returns 0 in case of success and negative number in case of error.
28 * Returning SEQ_SKIP means "discard this element and move on".
28 */ 29 */
29int seq_open(struct file *file, const struct seq_operations *op) 30int seq_open(struct file *file, const struct seq_operations *op)
30{ 31{
@@ -114,8 +115,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
114 if (!p || IS_ERR(p)) 115 if (!p || IS_ERR(p))
115 break; 116 break;
116 err = m->op->show(m, p); 117 err = m->op->show(m, p);
117 if (err) 118 if (err < 0)
118 break; 119 break;
120 if (unlikely(err))
121 m->count = 0;
119 if (m->count < m->size) 122 if (m->count < m->size)
120 goto Fill; 123 goto Fill;
121 m->op->stop(m, p); 124 m->op->stop(m, p);
@@ -140,9 +143,10 @@ Fill:
140 break; 143 break;
141 } 144 }
142 err = m->op->show(m, p); 145 err = m->op->show(m, p);
143 if (err || m->count == m->size) { 146 if (m->count == m->size || err) {
144 m->count = offs; 147 m->count = offs;
145 break; 148 if (likely(err <= 0))
149 break;
146 } 150 }
147 pos = next; 151 pos = next;
148 } 152 }
@@ -199,8 +203,12 @@ static int traverse(struct seq_file *m, loff_t offset)
199 if (IS_ERR(p)) 203 if (IS_ERR(p))
200 break; 204 break;
201 error = m->op->show(m, p); 205 error = m->op->show(m, p);
202 if (error) 206 if (error < 0)
203 break; 207 break;
208 if (unlikely(error)) {
209 error = 0;
210 m->count = 0;
211 }
204 if (m->count == m->size) 212 if (m->count == m->size)
205 goto Eoverflow; 213 goto Eoverflow;
206 if (pos + m->count > offset) { 214 if (pos + m->count > offset) {
@@ -239,7 +247,7 @@ Eoverflow:
239loff_t seq_lseek(struct file *file, loff_t offset, int origin) 247loff_t seq_lseek(struct file *file, loff_t offset, int origin)
240{ 248{
241 struct seq_file *m = (struct seq_file *)file->private_data; 249 struct seq_file *m = (struct seq_file *)file->private_data;
242 long long retval = -EINVAL; 250 loff_t retval = -EINVAL;
243 251
244 mutex_lock(&m->lock); 252 mutex_lock(&m->lock);
245 m->version = file->f_version; 253 m->version = file->f_version;
@@ -342,28 +350,40 @@ int seq_printf(struct seq_file *m, const char *f, ...)
342} 350}
343EXPORT_SYMBOL(seq_printf); 351EXPORT_SYMBOL(seq_printf);
344 352
353static char *mangle_path(char *s, char *p, char *esc)
354{
355 while (s <= p) {
356 char c = *p++;
357 if (!c) {
358 return s;
359 } else if (!strchr(esc, c)) {
360 *s++ = c;
361 } else if (s + 4 > p) {
362 break;
363 } else {
364 *s++ = '\\';
365 *s++ = '0' + ((c & 0300) >> 6);
366 *s++ = '0' + ((c & 070) >> 3);
367 *s++ = '0' + (c & 07);
368 }
369 }
370 return NULL;
371}
372
373/*
374 * return the absolute path of 'dentry' residing in mount 'mnt'.
375 */
345int seq_path(struct seq_file *m, struct path *path, char *esc) 376int seq_path(struct seq_file *m, struct path *path, char *esc)
346{ 377{
347 if (m->count < m->size) { 378 if (m->count < m->size) {
348 char *s = m->buf + m->count; 379 char *s = m->buf + m->count;
349 char *p = d_path(path, s, m->size - m->count); 380 char *p = d_path(path, s, m->size - m->count);
350 if (!IS_ERR(p)) { 381 if (!IS_ERR(p)) {
351 while (s <= p) { 382 s = mangle_path(s, p, esc);
352 char c = *p++; 383 if (s) {
353 if (!c) { 384 p = m->buf + m->count;
354 p = m->buf + m->count; 385 m->count = s - m->buf;
355 m->count = s - m->buf; 386 return s - p;
356 return s - p;
357 } else if (!strchr(esc, c)) {
358 *s++ = c;
359 } else if (s + 4 > p) {
360 break;
361 } else {
362 *s++ = '\\';
363 *s++ = '0' + ((c & 0300) >> 6);
364 *s++ = '0' + ((c & 070) >> 3);
365 *s++ = '0' + (c & 07);
366 }
367 } 387 }
368 } 388 }
369 } 389 }
@@ -372,6 +392,57 @@ int seq_path(struct seq_file *m, struct path *path, char *esc)
372} 392}
373EXPORT_SYMBOL(seq_path); 393EXPORT_SYMBOL(seq_path);
374 394
395/*
396 * Same as seq_path, but relative to supplied root.
397 *
398 * root may be changed, see __d_path().
399 */
400int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
401 char *esc)
402{
403 int err = -ENAMETOOLONG;
404 if (m->count < m->size) {
405 char *s = m->buf + m->count;
406 char *p;
407
408 spin_lock(&dcache_lock);
409 p = __d_path(path, root, s, m->size - m->count);
410 spin_unlock(&dcache_lock);
411 err = PTR_ERR(p);
412 if (!IS_ERR(p)) {
413 s = mangle_path(s, p, esc);
414 if (s) {
415 p = m->buf + m->count;
416 m->count = s - m->buf;
417 return 0;
418 }
419 }
420 }
421 m->count = m->size;
422 return err;
423}
424
425/*
426 * returns the path of the 'dentry' from the root of its filesystem.
427 */
428int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc)
429{
430 if (m->count < m->size) {
431 char *s = m->buf + m->count;
432 char *p = dentry_path(dentry, s, m->size - m->count);
433 if (!IS_ERR(p)) {
434 s = mangle_path(s, p, esc);
435 if (s) {
436 p = m->buf + m->count;
437 m->count = s - m->buf;
438 return s - p;
439 }
440 }
441 }
442 m->count = m->size;
443 return -1;
444}
445
375static void *single_start(struct seq_file *p, loff_t *pos) 446static void *single_start(struct seq_file *p, loff_t *pos)
376{ 447{
377 return NULL + (*pos == 0); 448 return NULL + (*pos == 0);