xref: /linux-6.15/include/linux/seq_buf.h (revision dcc4e572)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
23a161d99SSteven Rostedt (Red Hat) #ifndef _LINUX_SEQ_BUF_H
33a161d99SSteven Rostedt (Red Hat) #define _LINUX_SEQ_BUF_H
43a161d99SSteven Rostedt (Red Hat) 
53a161d99SSteven Rostedt (Red Hat) #include <linux/fs.h>
63a161d99SSteven Rostedt (Red Hat) 
73a161d99SSteven Rostedt (Red Hat) /*
83a161d99SSteven Rostedt (Red Hat)  * Trace sequences are used to allow a function to call several other functions
93a161d99SSteven Rostedt (Red Hat)  * to create a string of data to use.
103a161d99SSteven Rostedt (Red Hat)  */
113a161d99SSteven Rostedt (Red Hat) 
123a161d99SSteven Rostedt (Red Hat) /**
133a161d99SSteven Rostedt (Red Hat)  * seq_buf - seq buffer structure
143a161d99SSteven Rostedt (Red Hat)  * @buffer:	pointer to the buffer
153a161d99SSteven Rostedt (Red Hat)  * @size:	size of the buffer
163a161d99SSteven Rostedt (Red Hat)  * @len:	the amount of data inside the buffer
173a161d99SSteven Rostedt (Red Hat)  */
183a161d99SSteven Rostedt (Red Hat) struct seq_buf {
199a777793SSteven Rostedt (Red Hat) 	char			*buffer;
209a777793SSteven Rostedt (Red Hat) 	size_t			size;
219a777793SSteven Rostedt (Red Hat) 	size_t			len;
223a161d99SSteven Rostedt (Red Hat) };
233a161d99SSteven Rostedt (Red Hat) 
24*dcc4e572SKees Cook #define DECLARE_SEQ_BUF(NAME, SIZE)			\
25*dcc4e572SKees Cook 	char __ ## NAME ## _buffer[SIZE] = "";		\
26*dcc4e572SKees Cook 	struct seq_buf NAME = {				\
27*dcc4e572SKees Cook 		.buffer = &__ ## NAME ## _buffer,	\
28*dcc4e572SKees Cook 		.size = SIZE,				\
29*dcc4e572SKees Cook 	}
30*dcc4e572SKees Cook 
310736c033SSteven Rostedt (Red Hat) static inline void seq_buf_clear(struct seq_buf *s)
320736c033SSteven Rostedt (Red Hat) {
330736c033SSteven Rostedt (Red Hat) 	s->len = 0;
34*dcc4e572SKees Cook 	if (s->size)
35*dcc4e572SKees Cook 		s->buffer[0] = '\0';
360736c033SSteven Rostedt (Red Hat) }
370736c033SSteven Rostedt (Red Hat) 
383a161d99SSteven Rostedt (Red Hat) static inline void
39d9a9280aSArnd Bergmann seq_buf_init(struct seq_buf *s, char *buf, unsigned int size)
403a161d99SSteven Rostedt (Red Hat) {
413a161d99SSteven Rostedt (Red Hat) 	s->buffer = buf;
423a161d99SSteven Rostedt (Red Hat) 	s->size = size;
430736c033SSteven Rostedt (Red Hat) 	seq_buf_clear(s);
443a161d99SSteven Rostedt (Red Hat) }
453a161d99SSteven Rostedt (Red Hat) 
463a161d99SSteven Rostedt (Red Hat) /*
473a161d99SSteven Rostedt (Red Hat)  * seq_buf have a buffer that might overflow. When this happens
48845e31e1SJonathan Corbet  * len is set to be greater than size.
493a161d99SSteven Rostedt (Red Hat)  */
503a161d99SSteven Rostedt (Red Hat) static inline bool
513a161d99SSteven Rostedt (Red Hat) seq_buf_has_overflowed(struct seq_buf *s)
523a161d99SSteven Rostedt (Red Hat) {
538cd709aeSSteven Rostedt (Red Hat) 	return s->len > s->size;
543a161d99SSteven Rostedt (Red Hat) }
553a161d99SSteven Rostedt (Red Hat) 
563a161d99SSteven Rostedt (Red Hat) static inline void
573a161d99SSteven Rostedt (Red Hat) seq_buf_set_overflow(struct seq_buf *s)
583a161d99SSteven Rostedt (Red Hat) {
598cd709aeSSteven Rostedt (Red Hat) 	s->len = s->size + 1;
603a161d99SSteven Rostedt (Red Hat) }
613a161d99SSteven Rostedt (Red Hat) 
623a161d99SSteven Rostedt (Red Hat) /*
633a161d99SSteven Rostedt (Red Hat)  * How much buffer is left on the seq_buf?
643a161d99SSteven Rostedt (Red Hat)  */
653a161d99SSteven Rostedt (Red Hat) static inline unsigned int
663a161d99SSteven Rostedt (Red Hat) seq_buf_buffer_left(struct seq_buf *s)
673a161d99SSteven Rostedt (Red Hat) {
683a161d99SSteven Rostedt (Red Hat) 	if (seq_buf_has_overflowed(s))
693a161d99SSteven Rostedt (Red Hat) 		return 0;
703a161d99SSteven Rostedt (Red Hat) 
718cd709aeSSteven Rostedt (Red Hat) 	return s->size - s->len;
723a161d99SSteven Rostedt (Red Hat) }
733a161d99SSteven Rostedt (Red Hat) 
74eeab9815SSteven Rostedt (Red Hat) /* How much buffer was written? */
75eeab9815SSteven Rostedt (Red Hat) static inline unsigned int seq_buf_used(struct seq_buf *s)
76eeab9815SSteven Rostedt (Red Hat) {
77eeab9815SSteven Rostedt (Red Hat) 	return min(s->len, s->size);
78eeab9815SSteven Rostedt (Red Hat) }
79eeab9815SSteven Rostedt (Red Hat) 
8001cb06a4SSteven Rostedt (Red Hat) /**
81*dcc4e572SKees Cook  * seq_buf_str - get %NUL-terminated C string from seq_buf
82*dcc4e572SKees Cook  * @s: the seq_buf handle
83f2616c77SSteven Rostedt (VMware)  *
84f2616c77SSteven Rostedt (VMware)  * This makes sure that the buffer in @s is nul terminated and
85f2616c77SSteven Rostedt (VMware)  * safe to read as a string.
86f2616c77SSteven Rostedt (VMware)  *
87f2616c77SSteven Rostedt (VMware)  * Note, if this is called when the buffer has overflowed, then
88f2616c77SSteven Rostedt (VMware)  * the last byte of the buffer is zeroed, and the len will still
89f2616c77SSteven Rostedt (VMware)  * point passed it.
90f2616c77SSteven Rostedt (VMware)  *
91f2616c77SSteven Rostedt (VMware)  * After this function is called, s->buffer is safe to use
92f2616c77SSteven Rostedt (VMware)  * in string operations.
93*dcc4e572SKees Cook  *
94*dcc4e572SKees Cook  * Returns @s->buf after making sure it is terminated.
95f2616c77SSteven Rostedt (VMware)  */
96*dcc4e572SKees Cook static inline const char *seq_buf_str(struct seq_buf *s)
97f2616c77SSteven Rostedt (VMware) {
98f2616c77SSteven Rostedt (VMware) 	if (WARN_ON(s->size == 0))
99*dcc4e572SKees Cook 		return "";
100f2616c77SSteven Rostedt (VMware) 
101f2616c77SSteven Rostedt (VMware) 	if (seq_buf_buffer_left(s))
102f2616c77SSteven Rostedt (VMware) 		s->buffer[s->len] = 0;
103f2616c77SSteven Rostedt (VMware) 	else
104f2616c77SSteven Rostedt (VMware) 		s->buffer[s->size - 1] = 0;
105*dcc4e572SKees Cook 
106*dcc4e572SKees Cook 	return s->buffer;
107f2616c77SSteven Rostedt (VMware) }
108f2616c77SSteven Rostedt (VMware) 
109f2616c77SSteven Rostedt (VMware) /**
11001cb06a4SSteven Rostedt (Red Hat)  * seq_buf_get_buf - get buffer to write arbitrary data to
11101cb06a4SSteven Rostedt (Red Hat)  * @s: the seq_buf handle
11201cb06a4SSteven Rostedt (Red Hat)  * @bufp: the beginning of the buffer is stored here
11301cb06a4SSteven Rostedt (Red Hat)  *
11401cb06a4SSteven Rostedt (Red Hat)  * Return the number of bytes available in the buffer, or zero if
11501cb06a4SSteven Rostedt (Red Hat)  * there's no space.
11601cb06a4SSteven Rostedt (Red Hat)  */
11701cb06a4SSteven Rostedt (Red Hat) static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp)
11801cb06a4SSteven Rostedt (Red Hat) {
11901cb06a4SSteven Rostedt (Red Hat) 	WARN_ON(s->len > s->size + 1);
12001cb06a4SSteven Rostedt (Red Hat) 
12101cb06a4SSteven Rostedt (Red Hat) 	if (s->len < s->size) {
12201cb06a4SSteven Rostedt (Red Hat) 		*bufp = s->buffer + s->len;
12301cb06a4SSteven Rostedt (Red Hat) 		return s->size - s->len;
12401cb06a4SSteven Rostedt (Red Hat) 	}
12501cb06a4SSteven Rostedt (Red Hat) 
12601cb06a4SSteven Rostedt (Red Hat) 	*bufp = NULL;
12701cb06a4SSteven Rostedt (Red Hat) 	return 0;
12801cb06a4SSteven Rostedt (Red Hat) }
12901cb06a4SSteven Rostedt (Red Hat) 
13001cb06a4SSteven Rostedt (Red Hat) /**
13101cb06a4SSteven Rostedt (Red Hat)  * seq_buf_commit - commit data to the buffer
13201cb06a4SSteven Rostedt (Red Hat)  * @s: the seq_buf handle
13301cb06a4SSteven Rostedt (Red Hat)  * @num: the number of bytes to commit
13401cb06a4SSteven Rostedt (Red Hat)  *
13501cb06a4SSteven Rostedt (Red Hat)  * Commit @num bytes of data written to a buffer previously acquired
13601cb06a4SSteven Rostedt (Red Hat)  * by seq_buf_get.  To signal an error condition, or that the data
13701cb06a4SSteven Rostedt (Red Hat)  * didn't fit in the available space, pass a negative @num value.
13801cb06a4SSteven Rostedt (Red Hat)  */
13901cb06a4SSteven Rostedt (Red Hat) static inline void seq_buf_commit(struct seq_buf *s, int num)
14001cb06a4SSteven Rostedt (Red Hat) {
14101cb06a4SSteven Rostedt (Red Hat) 	if (num < 0) {
14201cb06a4SSteven Rostedt (Red Hat) 		seq_buf_set_overflow(s);
14301cb06a4SSteven Rostedt (Red Hat) 	} else {
14401cb06a4SSteven Rostedt (Red Hat) 		/* num must be negative on overflow */
14501cb06a4SSteven Rostedt (Red Hat) 		BUG_ON(s->len + num > s->size);
14601cb06a4SSteven Rostedt (Red Hat) 		s->len += num;
14701cb06a4SSteven Rostedt (Red Hat) 	}
14801cb06a4SSteven Rostedt (Red Hat) }
14901cb06a4SSteven Rostedt (Red Hat) 
1503a161d99SSteven Rostedt (Red Hat) extern __printf(2, 3)
1513a161d99SSteven Rostedt (Red Hat) int seq_buf_printf(struct seq_buf *s, const char *fmt, ...);
1523a161d99SSteven Rostedt (Red Hat) extern __printf(2, 0)
1533a161d99SSteven Rostedt (Red Hat) int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args);
1543a161d99SSteven Rostedt (Red Hat) extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s);
1553a161d99SSteven Rostedt (Red Hat) extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf,
156d0ed46b6SMatthew Wilcox (Oracle) 			   size_t start, int cnt);
1573a161d99SSteven Rostedt (Red Hat) extern int seq_buf_puts(struct seq_buf *s, const char *str);
1583a161d99SSteven Rostedt (Red Hat) extern int seq_buf_putc(struct seq_buf *s, unsigned char c);
1593a161d99SSteven Rostedt (Red Hat) extern int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len);
1603a161d99SSteven Rostedt (Red Hat) extern int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
1613a161d99SSteven Rostedt (Red Hat) 			      unsigned int len);
162dd23180aSSteven Rostedt (Red Hat) extern int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc);
163353cade3SPiotr Maziarz extern int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str,
164353cade3SPiotr Maziarz 			    int prefix_type, int rowsize, int groupsize,
165353cade3SPiotr Maziarz 			    const void *buf, size_t len, bool ascii);
1663a161d99SSteven Rostedt (Red Hat) 
1672448913eSSteven Rostedt (Red Hat) #ifdef CONFIG_BINARY_PRINTF
1682448913eSSteven Rostedt (Red Hat) extern int
1692448913eSSteven Rostedt (Red Hat) seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary);
1702448913eSSteven Rostedt (Red Hat) #endif
1712448913eSSteven Rostedt (Red Hat) 
17296928d90SSergey Senozhatsky void seq_buf_do_printk(struct seq_buf *s, const char *lvl);
17396928d90SSergey Senozhatsky 
1743a161d99SSteven Rostedt (Red Hat) #endif /* _LINUX_SEQ_BUF_H */
175