1
2
3
4
5
6
7
8#include <linux/fs.h>
9#include <linux/export.h>
10#include <linux/seq_file.h>
11#include <linux/slab.h>
12#include <linux/cred.h>
13
14#include <asm/uaccess.h>
15#include <asm/page.h>
16
17
18
19
20
21
22
23static bool seq_overflow(struct seq_file *m)
24{
25 return m->count == m->size;
26}
27
28static void seq_set_overflow(struct seq_file *m)
29{
30 m->count = m->size;
31}
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47int seq_open(struct file *file, const struct seq_operations *op)
48{
49 struct seq_file *p = file->private_data;
50
51 if (!p) {
52 p = kmalloc(sizeof(*p), GFP_KERNEL);
53 if (!p)
54 return -ENOMEM;
55 file->private_data = p;
56 }
57 memset(p, 0, sizeof(*p));
58 mutex_init(&p->lock);
59 p->op = op;
60#ifdef CONFIG_USER_NS
61 p->user_ns = file->f_cred->user_ns;
62#endif
63
64
65
66
67
68
69 file->f_version = 0;
70
71
72
73
74
75
76
77
78
79
80 file->f_mode &= ~FMODE_PWRITE;
81 return 0;
82}
83EXPORT_SYMBOL(seq_open);
84
85static int traverse(struct seq_file *m, loff_t offset)
86{
87 loff_t pos = 0, index;
88 int error = 0;
89 void *p;
90
91 m->version = 0;
92 index = 0;
93 m->count = m->from = 0;
94 if (!offset) {
95 m->index = index;
96 return 0;
97 }
98 if (!m->buf) {
99 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
100 if (!m->buf)
101 return -ENOMEM;
102 }
103 p = m->op->start(m, &index);
104 while (p) {
105 error = PTR_ERR(p);
106 if (IS_ERR(p))
107 break;
108 error = m->op->show(m, p);
109 if (error < 0)
110 break;
111 if (unlikely(error)) {
112 error = 0;
113 m->count = 0;
114 }
115 if (seq_overflow(m))
116 goto Eoverflow;
117 if (pos + m->count > offset) {
118 m->from = offset - pos;
119 m->count -= m->from;
120 m->index = index;
121 break;
122 }
123 pos += m->count;
124 m->count = 0;
125 if (pos == offset) {
126 index++;
127 m->index = index;
128 break;
129 }
130 p = m->op->next(m, p, &index);
131 }
132 m->op->stop(m, p);
133 m->index = index;
134 return error;
135
136Eoverflow:
137 m->op->stop(m, p);
138 kfree(m->buf);
139 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
140 return !m->buf ? -ENOMEM : -EAGAIN;
141}
142
143
144
145
146
147
148
149
150
151
152ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
153{
154 struct seq_file *m = file->private_data;
155 size_t copied = 0;
156 loff_t pos;
157 size_t n;
158 void *p;
159 int err = 0;
160
161 mutex_lock(&m->lock);
162
163
164
165
166
167
168
169
170
171
172
173
174 m->version = file->f_version;
175
176
177 if (unlikely(*ppos != m->read_pos)) {
178 while ((err = traverse(m, *ppos)) == -EAGAIN)
179 ;
180 if (err) {
181
182 m->read_pos = 0;
183 m->version = 0;
184 m->index = 0;
185 m->count = 0;
186 goto Done;
187 } else {
188 m->read_pos = *ppos;
189 }
190 }
191
192
193 if (!m->buf) {
194 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
195 if (!m->buf)
196 goto Enomem;
197 }
198
199 if (m->count) {
200 n = min(m->count, size);
201 err = copy_to_user(buf, m->buf + m->from, n);
202 if (err)
203 goto Efault;
204 m->count -= n;
205 m->from += n;
206 size -= n;
207 buf += n;
208 copied += n;
209 if (!m->count)
210 m->index++;
211 if (!size)
212 goto Done;
213 }
214
215 pos = m->index;
216 p = m->op->start(m, &pos);
217 while (1) {
218 err = PTR_ERR(p);
219 if (!p || IS_ERR(p))
220 break;
221 err = m->op->show(m, p);
222 if (err < 0)
223 break;
224 if (unlikely(err))
225 m->count = 0;
226 if (unlikely(!m->count)) {
227 p = m->op->next(m, p, &pos);
228 m->index = pos;
229 continue;
230 }
231 if (m->count < m->size)
232 goto Fill;
233 m->op->stop(m, p);
234 kfree(m->buf);
235 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
236 if (!m->buf)
237 goto Enomem;
238 m->count = 0;
239 m->version = 0;
240 pos = m->index;
241 p = m->op->start(m, &pos);
242 }
243 m->op->stop(m, p);
244 m->count = 0;
245 goto Done;
246Fill:
247
248 while (m->count < size) {
249 size_t offs = m->count;
250 loff_t next = pos;
251 p = m->op->next(m, p, &next);
252 if (!p || IS_ERR(p)) {
253 err = PTR_ERR(p);
254 break;
255 }
256 err = m->op->show(m, p);
257 if (seq_overflow(m) || err) {
258 m->count = offs;
259 if (likely(err <= 0))
260 break;
261 }
262 pos = next;
263 }
264 m->op->stop(m, p);
265 n = min(m->count, size);
266 err = copy_to_user(buf, m->buf, n);
267 if (err)
268 goto Efault;
269 copied += n;
270 m->count -= n;
271 if (m->count)
272 m->from = n;
273 else
274 pos++;
275 m->index = pos;
276Done:
277 if (!copied)
278 copied = err;
279 else {
280 *ppos += copied;
281 m->read_pos += copied;
282 }
283 file->f_version = m->version;
284 mutex_unlock(&m->lock);
285 return copied;
286Enomem:
287 err = -ENOMEM;
288 goto Done;
289Efault:
290 err = -EFAULT;
291 goto Done;
292}
293EXPORT_SYMBOL(seq_read);
294
295
296
297
298
299
300
301
302
303loff_t seq_lseek(struct file *file, loff_t offset, int origin)
304{
305 struct seq_file *m = file->private_data;
306 loff_t retval = -EINVAL;
307
308 mutex_lock(&m->lock);
309 m->version = file->f_version;
310 switch (origin) {
311 case 1:
312 offset += file->f_pos;
313 case 0:
314 if (offset < 0)
315 break;
316 retval = offset;
317 if (offset != m->read_pos) {
318 while ((retval=traverse(m, offset)) == -EAGAIN)
319 ;
320 if (retval) {
321
322 file->f_pos = 0;
323 m->read_pos = 0;
324 m->version = 0;
325 m->index = 0;
326 m->count = 0;
327 } else {
328 m->read_pos = offset;
329 retval = file->f_pos = offset;
330 }
331 }
332 }
333 file->f_version = m->version;
334 mutex_unlock(&m->lock);
335 return retval;
336}
337EXPORT_SYMBOL(seq_lseek);
338
339
340
341
342
343
344
345
346
347int seq_release(struct inode *inode, struct file *file)
348{
349 struct seq_file *m = file->private_data;
350 kfree(m->buf);
351 kfree(m);
352 return 0;
353}
354EXPORT_SYMBOL(seq_release);
355
356
357
358
359
360
361
362
363
364
365
366int seq_escape(struct seq_file *m, const char *s, const char *esc)
367{
368 char *end = m->buf + m->size;
369 char *p;
370 char c;
371
372 for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
373 if (!strchr(esc, c)) {
374 *p++ = c;
375 continue;
376 }
377 if (p + 3 < end) {
378 *p++ = '\\';
379 *p++ = '0' + ((c & 0300) >> 6);
380 *p++ = '0' + ((c & 070) >> 3);
381 *p++ = '0' + (c & 07);
382 continue;
383 }
384 seq_set_overflow(m);
385 return -1;
386 }
387 m->count = p - m->buf;
388 return 0;
389}
390EXPORT_SYMBOL(seq_escape);
391
392int seq_vprintf(struct seq_file *m, const char *f, va_list args)
393{
394 int len;
395
396 if (m->count < m->size) {
397 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
398 if (m->count + len < m->size) {
399 m->count += len;
400 return 0;
401 }
402 }
403 seq_set_overflow(m);
404 return -1;
405}
406EXPORT_SYMBOL(seq_vprintf);
407
408int seq_printf(struct seq_file *m, const char *f, ...)
409{
410 int ret;
411 va_list args;
412
413 va_start(args, f);
414 ret = seq_vprintf(m, f, args);
415 va_end(args);
416
417 return ret;
418}
419EXPORT_SYMBOL(seq_printf);
420
421
422
423
424
425
426
427
428
429
430
431
432char *mangle_path(char *s, const char *p, const char *esc)
433{
434 while (s <= p) {
435 char c = *p++;
436 if (!c) {
437 return s;
438 } else if (!strchr(esc, c)) {
439 *s++ = c;
440 } else if (s + 4 > p) {
441 break;
442 } else {
443 *s++ = '\\';
444 *s++ = '0' + ((c & 0300) >> 6);
445 *s++ = '0' + ((c & 070) >> 3);
446 *s++ = '0' + (c & 07);
447 }
448 }
449 return NULL;
450}
451EXPORT_SYMBOL(mangle_path);
452
453
454
455
456
457
458
459
460
461
462int seq_path(struct seq_file *m, const struct path *path, const char *esc)
463{
464 char *buf;
465 size_t size = seq_get_buf(m, &buf);
466 int res = -1;
467
468 if (size) {
469 char *p = d_path(path, buf, size);
470 if (!IS_ERR(p)) {
471 char *end = mangle_path(buf, p, esc);
472 if (end)
473 res = end - buf;
474 }
475 }
476 seq_commit(m, res);
477
478 return res;
479}
480EXPORT_SYMBOL(seq_path);
481
482
483
484
485int seq_path_root(struct seq_file *m, const struct path *path,
486 const struct path *root, const char *esc)
487{
488 char *buf;
489 size_t size = seq_get_buf(m, &buf);
490 int res = -ENAMETOOLONG;
491
492 if (size) {
493 char *p;
494
495 p = __d_path(path, root, buf, size);
496 if (!p)
497 return SEQ_SKIP;
498 res = PTR_ERR(p);
499 if (!IS_ERR(p)) {
500 char *end = mangle_path(buf, p, esc);
501 if (end)
502 res = end - buf;
503 else
504 res = -ENAMETOOLONG;
505 }
506 }
507 seq_commit(m, res);
508
509 return res < 0 && res != -ENAMETOOLONG ? res : 0;
510}
511
512
513
514
515int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)
516{
517 char *buf;
518 size_t size = seq_get_buf(m, &buf);
519 int res = -1;
520
521 if (size) {
522 char *p = dentry_path(dentry, buf, size);
523 if (!IS_ERR(p)) {
524 char *end = mangle_path(buf, p, esc);
525 if (end)
526 res = end - buf;
527 }
528 }
529 seq_commit(m, res);
530
531 return res;
532}
533
534int seq_bitmap(struct seq_file *m, const unsigned long *bits,
535 unsigned int nr_bits)
536{
537 if (m->count < m->size) {
538 int len = bitmap_scnprintf(m->buf + m->count,
539 m->size - m->count, bits, nr_bits);
540 if (m->count + len < m->size) {
541 m->count += len;
542 return 0;
543 }
544 }
545 seq_set_overflow(m);
546 return -1;
547}
548EXPORT_SYMBOL(seq_bitmap);
549
550int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
551 unsigned int nr_bits)
552{
553 if (m->count < m->size) {
554 int len = bitmap_scnlistprintf(m->buf + m->count,
555 m->size - m->count, bits, nr_bits);
556 if (m->count + len < m->size) {
557 m->count += len;
558 return 0;
559 }
560 }
561 seq_set_overflow(m);
562 return -1;
563}
564EXPORT_SYMBOL(seq_bitmap_list);
565
566static void *single_start(struct seq_file *p, loff_t *pos)
567{
568 return NULL + (*pos == 0);
569}
570
571static void *single_next(struct seq_file *p, void *v, loff_t *pos)
572{
573 ++*pos;
574 return NULL;
575}
576
577static void single_stop(struct seq_file *p, void *v)
578{
579}
580
581int single_open(struct file *file, int (*show)(struct seq_file *, void *),
582 void *data)
583{
584 struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
585 int res = -ENOMEM;
586
587 if (op) {
588 op->start = single_start;
589 op->next = single_next;
590 op->stop = single_stop;
591 op->show = show;
592 res = seq_open(file, op);
593 if (!res)
594 ((struct seq_file *)file->private_data)->private = data;
595 else
596 kfree(op);
597 }
598 return res;
599}
600EXPORT_SYMBOL(single_open);
601
602int single_release(struct inode *inode, struct file *file)
603{
604 const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
605 int res = seq_release(inode, file);
606 kfree(op);
607 return res;
608}
609EXPORT_SYMBOL(single_release);
610
611int seq_release_private(struct inode *inode, struct file *file)
612{
613 struct seq_file *seq = file->private_data;
614
615 kfree(seq->private);
616 seq->private = NULL;
617 return seq_release(inode, file);
618}
619EXPORT_SYMBOL(seq_release_private);
620
621void *__seq_open_private(struct file *f, const struct seq_operations *ops,
622 int psize)
623{
624 int rc;
625 void *private;
626 struct seq_file *seq;
627
628 private = kzalloc(psize, GFP_KERNEL);
629 if (private == NULL)
630 goto out;
631
632 rc = seq_open(f, ops);
633 if (rc < 0)
634 goto out_free;
635
636 seq = f->private_data;
637 seq->private = private;
638 return private;
639
640out_free:
641 kfree(private);
642out:
643 return NULL;
644}
645EXPORT_SYMBOL(__seq_open_private);
646
647int seq_open_private(struct file *filp, const struct seq_operations *ops,
648 int psize)
649{
650 return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
651}
652EXPORT_SYMBOL(seq_open_private);
653
654int seq_putc(struct seq_file *m, char c)
655{
656 if (m->count < m->size) {
657 m->buf[m->count++] = c;
658 return 0;
659 }
660 return -1;
661}
662EXPORT_SYMBOL(seq_putc);
663
664int seq_puts(struct seq_file *m, const char *s)
665{
666 int len = strlen(s);
667 if (m->count + len < m->size) {
668 memcpy(m->buf + m->count, s, len);
669 m->count += len;
670 return 0;
671 }
672 seq_set_overflow(m);
673 return -1;
674}
675EXPORT_SYMBOL(seq_puts);
676
677
678
679
680
681
682
683
684int seq_put_decimal_ull(struct seq_file *m, char delimiter,
685 unsigned long long num)
686{
687 int len;
688
689 if (m->count + 2 >= m->size)
690 goto overflow;
691
692 if (delimiter)
693 m->buf[m->count++] = delimiter;
694
695 if (num < 10) {
696 m->buf[m->count++] = num + '0';
697 return 0;
698 }
699
700 len = num_to_str(m->buf + m->count, m->size - m->count, num);
701 if (!len)
702 goto overflow;
703 m->count += len;
704 return 0;
705overflow:
706 seq_set_overflow(m);
707 return -1;
708}
709EXPORT_SYMBOL(seq_put_decimal_ull);
710
711int seq_put_decimal_ll(struct seq_file *m, char delimiter,
712 long long num)
713{
714 if (num < 0) {
715 if (m->count + 3 >= m->size) {
716 seq_set_overflow(m);
717 return -1;
718 }
719 if (delimiter)
720 m->buf[m->count++] = delimiter;
721 num = -num;
722 delimiter = '-';
723 }
724 return seq_put_decimal_ull(m, delimiter, num);
725
726}
727EXPORT_SYMBOL(seq_put_decimal_ll);
728
729
730
731
732
733
734
735
736
737int seq_write(struct seq_file *seq, const void *data, size_t len)
738{
739 if (seq->count + len < seq->size) {
740 memcpy(seq->buf + seq->count, data, len);
741 seq->count += len;
742 return 0;
743 }
744 seq_set_overflow(seq);
745 return -1;
746}
747EXPORT_SYMBOL(seq_write);
748
749struct list_head *seq_list_start(struct list_head *head, loff_t pos)
750{
751 struct list_head *lh;
752
753 list_for_each(lh, head)
754 if (pos-- == 0)
755 return lh;
756
757 return NULL;
758}
759EXPORT_SYMBOL(seq_list_start);
760
761struct list_head *seq_list_start_head(struct list_head *head, loff_t pos)
762{
763 if (!pos)
764 return head;
765
766 return seq_list_start(head, pos - 1);
767}
768EXPORT_SYMBOL(seq_list_start_head);
769
770struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
771{
772 struct list_head *lh;
773
774 lh = ((struct list_head *)v)->next;
775 ++*ppos;
776 return lh == head ? NULL : lh;
777}
778EXPORT_SYMBOL(seq_list_next);
779
780
781
782
783
784
785
786
787struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos)
788{
789 struct hlist_node *node;
790
791 hlist_for_each(node, head)
792 if (pos-- == 0)
793 return node;
794 return NULL;
795}
796EXPORT_SYMBOL(seq_hlist_start);
797
798
799
800
801
802
803
804
805
806struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos)
807{
808 if (!pos)
809 return SEQ_START_TOKEN;
810
811 return seq_hlist_start(head, pos - 1);
812}
813EXPORT_SYMBOL(seq_hlist_start_head);
814
815
816
817
818
819
820
821
822
823struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
824 loff_t *ppos)
825{
826 struct hlist_node *node = v;
827
828 ++*ppos;
829 if (v == SEQ_START_TOKEN)
830 return head->first;
831 else
832 return node->next;
833}
834EXPORT_SYMBOL(seq_hlist_next);
835
836
837
838
839
840
841
842
843
844
845
846
847struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
848 loff_t pos)
849{
850 struct hlist_node *node;
851
852 __hlist_for_each_rcu(node, head)
853 if (pos-- == 0)
854 return node;
855 return NULL;
856}
857EXPORT_SYMBOL(seq_hlist_start_rcu);
858
859
860
861
862
863
864
865
866
867
868
869
870
871struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
872 loff_t pos)
873{
874 if (!pos)
875 return SEQ_START_TOKEN;
876
877 return seq_hlist_start_rcu(head, pos - 1);
878}
879EXPORT_SYMBOL(seq_hlist_start_head_rcu);
880
881
882
883
884
885
886
887
888
889
890
891
892
893struct hlist_node *seq_hlist_next_rcu(void *v,
894 struct hlist_head *head,
895 loff_t *ppos)
896{
897 struct hlist_node *node = v;
898
899 ++*ppos;
900 if (v == SEQ_START_TOKEN)
901 return rcu_dereference(head->first);
902 else
903 return rcu_dereference(node->next);
904}
905EXPORT_SYMBOL(seq_hlist_next_rcu);
906