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