]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/seq_file.c
seq_file: move traverse so it can be used from seq_read
[net-next-2.6.git] / fs / seq_file.c
CommitLineData
1da177e4
LT
1/*
2 * linux/fs/seq_file.c
3 *
4 * helper functions for making synthetic files from sequences of records.
5 * initial implementation -- AV, Oct 2001.
6 */
7
8#include <linux/fs.h>
9#include <linux/module.h>
10#include <linux/seq_file.h>
11#include <linux/slab.h>
12
13#include <asm/uaccess.h>
14#include <asm/page.h>
15
16/**
17 * seq_open - initialize sequential file
18 * @file: file we initialize
19 * @op: method table describing the sequence
20 *
21 * seq_open() sets @file, associating it with a sequence described
22 * by @op. @op->start() sets the iterator up and returns the first
23 * element of sequence. @op->stop() shuts it down. @op->next()
24 * returns the next element of sequence. @op->show() prints element
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()
27 * returns 0 in case of success and negative number in case of error.
521b5d0c 28 * Returning SEQ_SKIP means "discard this element and move on".
1da177e4 29 */
15ad7cdc 30int seq_open(struct file *file, const struct seq_operations *op)
1da177e4 31{
1abe77b0
AV
32 struct seq_file *p = file->private_data;
33
34 if (!p) {
35 p = kmalloc(sizeof(*p), GFP_KERNEL);
36 if (!p)
37 return -ENOMEM;
38 file->private_data = p;
39 }
1da177e4 40 memset(p, 0, sizeof(*p));
0ac1759a 41 mutex_init(&p->lock);
1da177e4 42 p->op = op;
1da177e4
LT
43
44 /*
45 * Wrappers around seq_open(e.g. swaps_open) need to be
46 * aware of this. If they set f_version themselves, they
47 * should call seq_open first and then set f_version.
48 */
49 file->f_version = 0;
50
51 /* SEQ files support lseek, but not pread/pwrite */
52 file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
53 return 0;
54}
55EXPORT_SYMBOL(seq_open);
56
33da8892
EB
57static int traverse(struct seq_file *m, loff_t offset)
58{
59 loff_t pos = 0, index;
60 int error = 0;
61 void *p;
62
63 m->version = 0;
64 index = 0;
65 m->count = m->from = 0;
66 if (!offset) {
67 m->index = index;
68 return 0;
69 }
70 if (!m->buf) {
71 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
72 if (!m->buf)
73 return -ENOMEM;
74 }
75 p = m->op->start(m, &index);
76 while (p) {
77 error = PTR_ERR(p);
78 if (IS_ERR(p))
79 break;
80 error = m->op->show(m, p);
81 if (error < 0)
82 break;
83 if (unlikely(error)) {
84 error = 0;
85 m->count = 0;
86 }
87 if (m->count == m->size)
88 goto Eoverflow;
89 if (pos + m->count > offset) {
90 m->from = offset - pos;
91 m->count -= m->from;
92 m->index = index;
93 break;
94 }
95 pos += m->count;
96 m->count = 0;
97 if (pos == offset) {
98 index++;
99 m->index = index;
100 break;
101 }
102 p = m->op->next(m, p, &index);
103 }
104 m->op->stop(m, p);
105 return error;
106
107Eoverflow:
108 m->op->stop(m, p);
109 kfree(m->buf);
110 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
111 return !m->buf ? -ENOMEM : -EAGAIN;
112}
113
1da177e4
LT
114/**
115 * seq_read - ->read() method for sequential files.
67be2dd1
MW
116 * @file: the file to read from
117 * @buf: the buffer to read to
118 * @size: the maximum number of bytes to read
119 * @ppos: the current position in the file
1da177e4
LT
120 *
121 * Ready-made ->f_op->read()
122 */
123ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
124{
125 struct seq_file *m = (struct seq_file *)file->private_data;
126 size_t copied = 0;
127 loff_t pos;
128 size_t n;
129 void *p;
130 int err = 0;
131
0ac1759a 132 mutex_lock(&m->lock);
1da177e4
LT
133 /*
134 * seq_file->op->..m_start/m_stop/m_next may do special actions
135 * or optimisations based on the file->f_version, so we want to
136 * pass the file->f_version to those methods.
137 *
138 * seq_file->version is just copy of f_version, and seq_file
139 * methods can treat it simply as file version.
140 * It is copied in first and copied out after all operations.
141 * It is convenient to have it as part of structure to avoid the
142 * need of passing another argument to all the seq_file methods.
143 */
144 m->version = file->f_version;
145 /* grab buffer if we didn't have one */
146 if (!m->buf) {
147 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
148 if (!m->buf)
149 goto Enomem;
150 }
151 /* if not empty - flush it first */
152 if (m->count) {
153 n = min(m->count, size);
154 err = copy_to_user(buf, m->buf + m->from, n);
155 if (err)
156 goto Efault;
157 m->count -= n;
158 m->from += n;
159 size -= n;
160 buf += n;
161 copied += n;
162 if (!m->count)
163 m->index++;
164 if (!size)
165 goto Done;
166 }
167 /* we need at least one record in buffer */
4cdfe84b
AV
168 pos = m->index;
169 p = m->op->start(m, &pos);
1da177e4 170 while (1) {
1da177e4
LT
171 err = PTR_ERR(p);
172 if (!p || IS_ERR(p))
173 break;
174 err = m->op->show(m, p);
521b5d0c 175 if (err < 0)
1da177e4 176 break;
521b5d0c
AV
177 if (unlikely(err))
178 m->count = 0;
4cdfe84b
AV
179 if (unlikely(!m->count)) {
180 p = m->op->next(m, p, &pos);
181 m->index = pos;
182 continue;
183 }
1da177e4
LT
184 if (m->count < m->size)
185 goto Fill;
186 m->op->stop(m, p);
187 kfree(m->buf);
188 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
189 if (!m->buf)
190 goto Enomem;
191 m->count = 0;
192 m->version = 0;
4cdfe84b
AV
193 pos = m->index;
194 p = m->op->start(m, &pos);
1da177e4
LT
195 }
196 m->op->stop(m, p);
197 m->count = 0;
198 goto Done;
199Fill:
200 /* they want more? let's try to get some more */
201 while (m->count < size) {
202 size_t offs = m->count;
203 loff_t next = pos;
204 p = m->op->next(m, p, &next);
205 if (!p || IS_ERR(p)) {
206 err = PTR_ERR(p);
207 break;
208 }
209 err = m->op->show(m, p);
521b5d0c 210 if (m->count == m->size || err) {
1da177e4 211 m->count = offs;
521b5d0c
AV
212 if (likely(err <= 0))
213 break;
1da177e4
LT
214 }
215 pos = next;
216 }
217 m->op->stop(m, p);
218 n = min(m->count, size);
219 err = copy_to_user(buf, m->buf, n);
220 if (err)
221 goto Efault;
222 copied += n;
223 m->count -= n;
224 if (m->count)
225 m->from = n;
226 else
227 pos++;
228 m->index = pos;
229Done:
230 if (!copied)
231 copied = err;
232 else
233 *ppos += copied;
234 file->f_version = m->version;
0ac1759a 235 mutex_unlock(&m->lock);
1da177e4
LT
236 return copied;
237Enomem:
238 err = -ENOMEM;
239 goto Done;
240Efault:
241 err = -EFAULT;
242 goto Done;
243}
244EXPORT_SYMBOL(seq_read);
245
1da177e4
LT
246/**
247 * seq_lseek - ->llseek() method for sequential files.
67be2dd1
MW
248 * @file: the file in question
249 * @offset: new position
250 * @origin: 0 for absolute, 1 for relative position
1da177e4
LT
251 *
252 * Ready-made ->f_op->llseek()
253 */
254loff_t seq_lseek(struct file *file, loff_t offset, int origin)
255{
256 struct seq_file *m = (struct seq_file *)file->private_data;
16abef0e 257 loff_t retval = -EINVAL;
1da177e4 258
0ac1759a 259 mutex_lock(&m->lock);
1da177e4
LT
260 m->version = file->f_version;
261 switch (origin) {
262 case 1:
263 offset += file->f_pos;
264 case 0:
265 if (offset < 0)
266 break;
267 retval = offset;
268 if (offset != file->f_pos) {
269 while ((retval=traverse(m, offset)) == -EAGAIN)
270 ;
271 if (retval) {
272 /* with extreme prejudice... */
273 file->f_pos = 0;
274 m->version = 0;
275 m->index = 0;
276 m->count = 0;
277 } else {
278 retval = file->f_pos = offset;
279 }
280 }
281 }
1da177e4 282 file->f_version = m->version;
00c5746d 283 mutex_unlock(&m->lock);
1da177e4
LT
284 return retval;
285}
286EXPORT_SYMBOL(seq_lseek);
287
288/**
289 * seq_release - free the structures associated with sequential file.
290 * @file: file in question
0f7fc9e4 291 * @inode: file->f_path.dentry->d_inode
1da177e4
LT
292 *
293 * Frees the structures associated with sequential file; can be used
294 * as ->f_op->release() if you don't have private data to destroy.
295 */
296int seq_release(struct inode *inode, struct file *file)
297{
298 struct seq_file *m = (struct seq_file *)file->private_data;
299 kfree(m->buf);
300 kfree(m);
301 return 0;
302}
303EXPORT_SYMBOL(seq_release);
304
305/**
306 * seq_escape - print string into buffer, escaping some characters
307 * @m: target buffer
308 * @s: string
309 * @esc: set of characters that need escaping
310 *
311 * Puts string into buffer, replacing each occurrence of character from
312 * @esc with usual octal escape. Returns 0 in case of success, -1 - in
313 * case of overflow.
314 */
315int seq_escape(struct seq_file *m, const char *s, const char *esc)
316{
317 char *end = m->buf + m->size;
318 char *p;
319 char c;
320
321 for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
322 if (!strchr(esc, c)) {
323 *p++ = c;
324 continue;
325 }
326 if (p + 3 < end) {
327 *p++ = '\\';
328 *p++ = '0' + ((c & 0300) >> 6);
329 *p++ = '0' + ((c & 070) >> 3);
330 *p++ = '0' + (c & 07);
331 continue;
332 }
333 m->count = m->size;
334 return -1;
335 }
336 m->count = p - m->buf;
337 return 0;
338}
339EXPORT_SYMBOL(seq_escape);
340
341int seq_printf(struct seq_file *m, const char *f, ...)
342{
343 va_list args;
344 int len;
345
346 if (m->count < m->size) {
347 va_start(args, f);
348 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
349 va_end(args);
350 if (m->count + len < m->size) {
351 m->count += len;
352 return 0;
353 }
354 }
355 m->count = m->size;
356 return -1;
357}
358EXPORT_SYMBOL(seq_printf);
359
74e2f334 360/**
958086d1
TE
361 * mangle_path - mangle and copy path to buffer beginning
362 * @s: buffer start
363 * @p: beginning of path in above buffer
364 * @esc: set of characters that need escaping
74e2f334
TE
365 *
366 * Copy the path from @p to @s, replacing each occurrence of character from
367 * @esc with usual octal escape.
368 * Returns pointer past last written character in @s, or NULL in case of
369 * failure.
370 */
371char *mangle_path(char *s, char *p, char *esc)
6092d048
RP
372{
373 while (s <= p) {
374 char c = *p++;
375 if (!c) {
376 return s;
377 } else if (!strchr(esc, c)) {
378 *s++ = c;
379 } else if (s + 4 > p) {
380 break;
381 } else {
382 *s++ = '\\';
383 *s++ = '0' + ((c & 0300) >> 6);
384 *s++ = '0' + ((c & 070) >> 3);
385 *s++ = '0' + (c & 07);
386 }
387 }
388 return NULL;
389}
604094f4 390EXPORT_SYMBOL(mangle_path);
6092d048 391
52afeefb
AV
392/**
393 * seq_path - seq_file interface to print a pathname
394 * @m: the seq_file handle
395 * @path: the struct path to print
396 * @esc: set of characters to escape in the output
397 *
398 * return the absolute path of 'path', as represented by the
399 * dentry / mnt pair in the path parameter.
6092d048 400 */
c32c2f63 401int seq_path(struct seq_file *m, struct path *path, char *esc)
1da177e4
LT
402{
403 if (m->count < m->size) {
404 char *s = m->buf + m->count;
cf28b486 405 char *p = d_path(path, s, m->size - m->count);
1da177e4 406 if (!IS_ERR(p)) {
6092d048
RP
407 s = mangle_path(s, p, esc);
408 if (s) {
409 p = m->buf + m->count;
410 m->count = s - m->buf;
411 return s - p;
1da177e4
LT
412 }
413 }
414 }
415 m->count = m->size;
416 return -1;
417}
418EXPORT_SYMBOL(seq_path);
419
9d1bc601
MS
420/*
421 * Same as seq_path, but relative to supplied root.
422 *
423 * root may be changed, see __d_path().
424 */
425int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
426 char *esc)
427{
428 int err = -ENAMETOOLONG;
429 if (m->count < m->size) {
430 char *s = m->buf + m->count;
431 char *p;
432
433 spin_lock(&dcache_lock);
434 p = __d_path(path, root, s, m->size - m->count);
435 spin_unlock(&dcache_lock);
436 err = PTR_ERR(p);
437 if (!IS_ERR(p)) {
438 s = mangle_path(s, p, esc);
439 if (s) {
440 p = m->buf + m->count;
441 m->count = s - m->buf;
442 return 0;
443 }
444 }
445 }
446 m->count = m->size;
447 return err;
448}
449
6092d048
RP
450/*
451 * returns the path of the 'dentry' from the root of its filesystem.
452 */
453int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc)
454{
455 if (m->count < m->size) {
456 char *s = m->buf + m->count;
457 char *p = dentry_path(dentry, s, m->size - m->count);
458 if (!IS_ERR(p)) {
459 s = mangle_path(s, p, esc);
460 if (s) {
461 p = m->buf + m->count;
462 m->count = s - m->buf;
463 return s - p;
464 }
465 }
466 }
467 m->count = m->size;
468 return -1;
469}
470
cb78a0ce
RR
471int seq_bitmap(struct seq_file *m, const unsigned long *bits,
472 unsigned int nr_bits)
50ac2d69 473{
85dd030e
LJ
474 if (m->count < m->size) {
475 int len = bitmap_scnprintf(m->buf + m->count,
476 m->size - m->count, bits, nr_bits);
477 if (m->count + len < m->size) {
478 m->count += len;
479 return 0;
480 }
50ac2d69
AD
481 }
482 m->count = m->size;
483 return -1;
484}
85dd030e 485EXPORT_SYMBOL(seq_bitmap);
50ac2d69 486
3eda2011
LJ
487int seq_bitmap_list(struct seq_file *m, unsigned long *bits,
488 unsigned int nr_bits)
489{
490 if (m->count < m->size) {
491 int len = bitmap_scnlistprintf(m->buf + m->count,
492 m->size - m->count, bits, nr_bits);
493 if (m->count + len < m->size) {
494 m->count += len;
495 return 0;
496 }
497 }
498 m->count = m->size;
499 return -1;
500}
501EXPORT_SYMBOL(seq_bitmap_list);
502
1da177e4
LT
503static void *single_start(struct seq_file *p, loff_t *pos)
504{
505 return NULL + (*pos == 0);
506}
507
508static void *single_next(struct seq_file *p, void *v, loff_t *pos)
509{
510 ++*pos;
511 return NULL;
512}
513
514static void single_stop(struct seq_file *p, void *v)
515{
516}
517
518int single_open(struct file *file, int (*show)(struct seq_file *, void *),
519 void *data)
520{
521 struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
522 int res = -ENOMEM;
523
524 if (op) {
525 op->start = single_start;
526 op->next = single_next;
527 op->stop = single_stop;
528 op->show = show;
529 res = seq_open(file, op);
530 if (!res)
531 ((struct seq_file *)file->private_data)->private = data;
532 else
533 kfree(op);
534 }
535 return res;
536}
537EXPORT_SYMBOL(single_open);
538
539int single_release(struct inode *inode, struct file *file)
540{
15ad7cdc 541 const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
1da177e4
LT
542 int res = seq_release(inode, file);
543 kfree(op);
544 return res;
545}
546EXPORT_SYMBOL(single_release);
547
548int seq_release_private(struct inode *inode, struct file *file)
549{
550 struct seq_file *seq = file->private_data;
551
552 kfree(seq->private);
553 seq->private = NULL;
554 return seq_release(inode, file);
555}
556EXPORT_SYMBOL(seq_release_private);
557
39699037
PE
558void *__seq_open_private(struct file *f, const struct seq_operations *ops,
559 int psize)
560{
561 int rc;
562 void *private;
563 struct seq_file *seq;
564
565 private = kzalloc(psize, GFP_KERNEL);
566 if (private == NULL)
567 goto out;
568
569 rc = seq_open(f, ops);
570 if (rc < 0)
571 goto out_free;
572
573 seq = f->private_data;
574 seq->private = private;
575 return private;
576
577out_free:
578 kfree(private);
579out:
580 return NULL;
581}
582EXPORT_SYMBOL(__seq_open_private);
583
584int seq_open_private(struct file *filp, const struct seq_operations *ops,
585 int psize)
586{
587 return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
588}
589EXPORT_SYMBOL(seq_open_private);
590
1da177e4
LT
591int seq_putc(struct seq_file *m, char c)
592{
593 if (m->count < m->size) {
594 m->buf[m->count++] = c;
595 return 0;
596 }
597 return -1;
598}
599EXPORT_SYMBOL(seq_putc);
600
601int seq_puts(struct seq_file *m, const char *s)
602{
603 int len = strlen(s);
604 if (m->count + len < m->size) {
605 memcpy(m->buf + m->count, s, len);
606 m->count += len;
607 return 0;
608 }
609 m->count = m->size;
610 return -1;
611}
612EXPORT_SYMBOL(seq_puts);
bcf67e16
PE
613
614struct list_head *seq_list_start(struct list_head *head, loff_t pos)
615{
616 struct list_head *lh;
617
618 list_for_each(lh, head)
619 if (pos-- == 0)
620 return lh;
621
622 return NULL;
623}
624
625EXPORT_SYMBOL(seq_list_start);
626
627struct list_head *seq_list_start_head(struct list_head *head, loff_t pos)
628{
629 if (!pos)
630 return head;
631
632 return seq_list_start(head, pos - 1);
633}
634
635EXPORT_SYMBOL(seq_list_start_head);
636
637struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
638{
639 struct list_head *lh;
640
641 lh = ((struct list_head *)v)->next;
642 ++*ppos;
643 return lh == head ? NULL : lh;
644}
645
646EXPORT_SYMBOL(seq_list_next);