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