1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * seq_buf.c |
4 | * |
5 | * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> |
6 | * |
7 | * The seq_buf is a handy tool that allows you to pass a descriptor around |
8 | * to a buffer that other functions can write to. It is similar to the |
9 | * seq_file functionality but has some differences. |
10 | * |
11 | * To use it, the seq_buf must be initialized with seq_buf_init(). |
12 | * This will set up the counters within the descriptor. You can call |
13 | * seq_buf_init() more than once to reset the seq_buf to start |
14 | * from scratch. |
15 | */ |
16 | #include <linux/uaccess.h> |
17 | #include <linux/seq_file.h> |
18 | #include <linux/seq_buf.h> |
19 | |
20 | /** |
21 | * seq_buf_can_fit - can the new data fit in the current buffer? |
22 | * @s: the seq_buf descriptor |
23 | * @len: The length to see if it can fit in the current buffer |
24 | * |
25 | * Returns true if there's enough unused space in the seq_buf buffer |
26 | * to fit the amount of new data according to @len. |
27 | */ |
28 | static bool seq_buf_can_fit(struct seq_buf *s, size_t len) |
29 | { |
30 | return s->len + len <= s->size; |
31 | } |
32 | |
33 | /** |
34 | * seq_buf_print_seq - move the contents of seq_buf into a seq_file |
35 | * @m: the seq_file descriptor that is the destination |
36 | * @s: the seq_buf descriptor that is the source. |
37 | * |
38 | * Returns zero on success, non zero otherwise |
39 | */ |
40 | int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) |
41 | { |
42 | unsigned int len = seq_buf_used(s); |
43 | |
44 | return seq_write(seq: m, data: s->buffer, len); |
45 | } |
46 | |
47 | /** |
48 | * seq_buf_vprintf - sequence printing of information. |
49 | * @s: seq_buf descriptor |
50 | * @fmt: printf format string |
51 | * @args: va_list of arguments from a printf() type function |
52 | * |
53 | * Writes a vnprintf() format into the sequencce buffer. |
54 | * |
55 | * Returns zero on success, -1 on overflow. |
56 | */ |
57 | int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) |
58 | { |
59 | int len; |
60 | |
61 | WARN_ON(s->size == 0); |
62 | |
63 | if (s->len < s->size) { |
64 | len = vsnprintf(buf: s->buffer + s->len, size: s->size - s->len, fmt, args); |
65 | if (s->len + len < s->size) { |
66 | s->len += len; |
67 | return 0; |
68 | } |
69 | } |
70 | seq_buf_set_overflow(s); |
71 | return -1; |
72 | } |
73 | |
74 | /** |
75 | * seq_buf_printf - sequence printing of information |
76 | * @s: seq_buf descriptor |
77 | * @fmt: printf format string |
78 | * |
79 | * Writes a printf() format into the sequence buffer. |
80 | * |
81 | * Returns zero on success, -1 on overflow. |
82 | */ |
83 | int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) |
84 | { |
85 | va_list ap; |
86 | int ret; |
87 | |
88 | va_start(ap, fmt); |
89 | ret = seq_buf_vprintf(s, fmt, args: ap); |
90 | va_end(ap); |
91 | |
92 | return ret; |
93 | } |
94 | EXPORT_SYMBOL_GPL(seq_buf_printf); |
95 | |
96 | /** |
97 | * seq_buf_do_printk - printk seq_buf line by line |
98 | * @s: seq_buf descriptor |
99 | * @lvl: printk level |
100 | * |
101 | * printk()-s a multi-line sequential buffer line by line. The function |
102 | * makes sure that the buffer in @s is nul terminated and safe to read |
103 | * as a string. |
104 | */ |
105 | void seq_buf_do_printk(struct seq_buf *s, const char *lvl) |
106 | { |
107 | const char *start, *lf; |
108 | |
109 | if (s->size == 0 || s->len == 0) |
110 | return; |
111 | |
112 | start = seq_buf_str(s); |
113 | while ((lf = strchr(start, '\n'))) { |
114 | int len = lf - start + 1; |
115 | |
116 | printk("%s%.*s" , lvl, len, start); |
117 | start = ++lf; |
118 | } |
119 | |
120 | /* No trailing LF */ |
121 | if (start < s->buffer + s->len) |
122 | printk("%s%s\n" , lvl, start); |
123 | } |
124 | EXPORT_SYMBOL_GPL(seq_buf_do_printk); |
125 | |
126 | #ifdef CONFIG_BINARY_PRINTF |
127 | /** |
128 | * seq_buf_bprintf - Write the printf string from binary arguments |
129 | * @s: seq_buf descriptor |
130 | * @fmt: The format string for the @binary arguments |
131 | * @binary: The binary arguments for @fmt. |
132 | * |
133 | * When recording in a fast path, a printf may be recorded with just |
134 | * saving the format and the arguments as they were passed to the |
135 | * function, instead of wasting cycles converting the arguments into |
136 | * ASCII characters. Instead, the arguments are saved in a 32 bit |
137 | * word array that is defined by the format string constraints. |
138 | * |
139 | * This function will take the format and the binary array and finish |
140 | * the conversion into the ASCII string within the buffer. |
141 | * |
142 | * Returns zero on success, -1 on overflow. |
143 | */ |
144 | int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) |
145 | { |
146 | unsigned int len = seq_buf_buffer_left(s); |
147 | int ret; |
148 | |
149 | WARN_ON(s->size == 0); |
150 | |
151 | if (s->len < s->size) { |
152 | ret = bstr_printf(buf: s->buffer + s->len, size: len, fmt, bin_buf: binary); |
153 | if (s->len + ret < s->size) { |
154 | s->len += ret; |
155 | return 0; |
156 | } |
157 | } |
158 | seq_buf_set_overflow(s); |
159 | return -1; |
160 | } |
161 | #endif /* CONFIG_BINARY_PRINTF */ |
162 | |
163 | /** |
164 | * seq_buf_puts - sequence printing of simple string |
165 | * @s: seq_buf descriptor |
166 | * @str: simple string to record |
167 | * |
168 | * Copy a simple string into the sequence buffer. |
169 | * |
170 | * Returns zero on success, -1 on overflow |
171 | */ |
172 | int seq_buf_puts(struct seq_buf *s, const char *str) |
173 | { |
174 | size_t len = strlen(str); |
175 | |
176 | WARN_ON(s->size == 0); |
177 | |
178 | /* Add 1 to len for the trailing null byte which must be there */ |
179 | len += 1; |
180 | |
181 | if (seq_buf_can_fit(s, len)) { |
182 | memcpy(s->buffer + s->len, str, len); |
183 | /* Don't count the trailing null byte against the capacity */ |
184 | s->len += len - 1; |
185 | return 0; |
186 | } |
187 | seq_buf_set_overflow(s); |
188 | return -1; |
189 | } |
190 | EXPORT_SYMBOL_GPL(seq_buf_puts); |
191 | |
192 | /** |
193 | * seq_buf_putc - sequence printing of simple character |
194 | * @s: seq_buf descriptor |
195 | * @c: simple character to record |
196 | * |
197 | * Copy a single character into the sequence buffer. |
198 | * |
199 | * Returns zero on success, -1 on overflow |
200 | */ |
201 | int seq_buf_putc(struct seq_buf *s, unsigned char c) |
202 | { |
203 | WARN_ON(s->size == 0); |
204 | |
205 | if (seq_buf_can_fit(s, len: 1)) { |
206 | s->buffer[s->len++] = c; |
207 | return 0; |
208 | } |
209 | seq_buf_set_overflow(s); |
210 | return -1; |
211 | } |
212 | EXPORT_SYMBOL_GPL(seq_buf_putc); |
213 | |
214 | /** |
215 | * seq_buf_putmem - write raw data into the sequenc buffer |
216 | * @s: seq_buf descriptor |
217 | * @mem: The raw memory to copy into the buffer |
218 | * @len: The length of the raw memory to copy (in bytes) |
219 | * |
220 | * There may be cases where raw memory needs to be written into the |
221 | * buffer and a strcpy() would not work. Using this function allows |
222 | * for such cases. |
223 | * |
224 | * Returns zero on success, -1 on overflow |
225 | */ |
226 | int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) |
227 | { |
228 | WARN_ON(s->size == 0); |
229 | |
230 | if (seq_buf_can_fit(s, len)) { |
231 | memcpy(s->buffer + s->len, mem, len); |
232 | s->len += len; |
233 | return 0; |
234 | } |
235 | seq_buf_set_overflow(s); |
236 | return -1; |
237 | } |
238 | |
239 | #define MAX_MEMHEX_BYTES 8U |
240 | #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) |
241 | |
242 | /** |
243 | * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex |
244 | * @s: seq_buf descriptor |
245 | * @mem: The raw memory to write its hex ASCII representation of |
246 | * @len: The length of the raw memory to copy (in bytes) |
247 | * |
248 | * This is similar to seq_buf_putmem() except instead of just copying the |
249 | * raw memory into the buffer it writes its ASCII representation of it |
250 | * in hex characters. |
251 | * |
252 | * Returns zero on success, -1 on overflow |
253 | */ |
254 | int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, |
255 | unsigned int len) |
256 | { |
257 | unsigned char hex[HEX_CHARS]; |
258 | const unsigned char *data = mem; |
259 | unsigned int start_len; |
260 | int i, j; |
261 | |
262 | WARN_ON(s->size == 0); |
263 | |
264 | BUILD_BUG_ON(MAX_MEMHEX_BYTES * 2 >= HEX_CHARS); |
265 | |
266 | while (len) { |
267 | start_len = min(len, MAX_MEMHEX_BYTES); |
268 | #ifdef __BIG_ENDIAN |
269 | for (i = 0, j = 0; i < start_len; i++) { |
270 | #else |
271 | for (i = start_len-1, j = 0; i >= 0; i--) { |
272 | #endif |
273 | hex[j++] = hex_asc_hi(data[i]); |
274 | hex[j++] = hex_asc_lo(data[i]); |
275 | } |
276 | if (WARN_ON_ONCE(j == 0 || j/2 > len)) |
277 | break; |
278 | |
279 | /* j increments twice per loop */ |
280 | hex[j++] = ' '; |
281 | |
282 | seq_buf_putmem(s, mem: hex, len: j); |
283 | if (seq_buf_has_overflowed(s)) |
284 | return -1; |
285 | |
286 | len -= start_len; |
287 | data += start_len; |
288 | } |
289 | return 0; |
290 | } |
291 | |
292 | /** |
293 | * seq_buf_path - copy a path into the sequence buffer |
294 | * @s: seq_buf descriptor |
295 | * @path: path to write into the sequence buffer. |
296 | * @esc: set of characters to escape in the output |
297 | * |
298 | * Write a path name into the sequence buffer. |
299 | * |
300 | * Returns the number of written bytes on success, -1 on overflow |
301 | */ |
302 | int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) |
303 | { |
304 | char *buf; |
305 | size_t size = seq_buf_get_buf(s, bufp: &buf); |
306 | int res = -1; |
307 | |
308 | WARN_ON(s->size == 0); |
309 | |
310 | if (size) { |
311 | char *p = d_path(path, buf, size); |
312 | if (!IS_ERR(ptr: p)) { |
313 | char *end = mangle_path(s: buf, p, esc); |
314 | if (end) |
315 | res = end - buf; |
316 | } |
317 | } |
318 | seq_buf_commit(s, num: res); |
319 | |
320 | return res; |
321 | } |
322 | |
323 | /** |
324 | * seq_buf_to_user - copy the sequence buffer to user space |
325 | * @s: seq_buf descriptor |
326 | * @ubuf: The userspace memory location to copy to |
327 | * @start: The first byte in the buffer to copy |
328 | * @cnt: The amount to copy |
329 | * |
330 | * Copies the sequence buffer into the userspace memory pointed to |
331 | * by @ubuf. It starts from @start and writes up to @cnt characters |
332 | * or until it reaches the end of the content in the buffer (@s->len), |
333 | * whichever comes first. |
334 | * |
335 | * On success, it returns a positive number of the number of bytes |
336 | * it copied. |
337 | * |
338 | * On failure it returns -EBUSY if all of the content in the |
339 | * sequence has been already read, which includes nothing in the |
340 | * sequence (@s->len == @start). |
341 | * |
342 | * Returns -EFAULT if the copy to userspace fails. |
343 | */ |
344 | int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, size_t start, int cnt) |
345 | { |
346 | int len; |
347 | int ret; |
348 | |
349 | if (!cnt) |
350 | return 0; |
351 | |
352 | len = seq_buf_used(s); |
353 | |
354 | if (len <= start) |
355 | return -EBUSY; |
356 | |
357 | len -= start; |
358 | if (cnt > len) |
359 | cnt = len; |
360 | ret = copy_to_user(to: ubuf, from: s->buffer + start, n: cnt); |
361 | if (ret == cnt) |
362 | return -EFAULT; |
363 | |
364 | return cnt - ret; |
365 | } |
366 | |
367 | /** |
368 | * seq_buf_hex_dump - print formatted hex dump into the sequence buffer |
369 | * @s: seq_buf descriptor |
370 | * @prefix_str: string to prefix each line with; |
371 | * caller supplies trailing spaces for alignment if desired |
372 | * @prefix_type: controls whether prefix of an offset, address, or none |
373 | * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) |
374 | * @rowsize: number of bytes to print per line; must be 16 or 32 |
375 | * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) |
376 | * @buf: data blob to dump |
377 | * @len: number of bytes in the @buf |
378 | * @ascii: include ASCII after the hex output |
379 | * |
380 | * Function is an analogue of print_hex_dump() and thus has similar interface. |
381 | * |
382 | * linebuf size is maximal length for one line. |
383 | * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for |
384 | * separating space |
385 | * 2 - spaces separating hex dump and ascii representation |
386 | * 32 - ascii representation |
387 | * 1 - terminating '\0' |
388 | * |
389 | * Returns zero on success, -1 on overflow |
390 | */ |
391 | int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type, |
392 | int rowsize, int groupsize, |
393 | const void *buf, size_t len, bool ascii) |
394 | { |
395 | const u8 *ptr = buf; |
396 | int i, linelen, remaining = len; |
397 | unsigned char linebuf[32 * 3 + 2 + 32 + 1]; |
398 | int ret; |
399 | |
400 | if (rowsize != 16 && rowsize != 32) |
401 | rowsize = 16; |
402 | |
403 | for (i = 0; i < len; i += rowsize) { |
404 | linelen = min(remaining, rowsize); |
405 | remaining -= rowsize; |
406 | |
407 | hex_dump_to_buffer(buf: ptr + i, len: linelen, rowsize, groupsize, |
408 | linebuf, linebuflen: sizeof(linebuf), ascii); |
409 | |
410 | switch (prefix_type) { |
411 | case DUMP_PREFIX_ADDRESS: |
412 | ret = seq_buf_printf(s, "%s%p: %s\n" , |
413 | prefix_str, ptr + i, linebuf); |
414 | break; |
415 | case DUMP_PREFIX_OFFSET: |
416 | ret = seq_buf_printf(s, "%s%.8x: %s\n" , |
417 | prefix_str, i, linebuf); |
418 | break; |
419 | default: |
420 | ret = seq_buf_printf(s, "%s%s\n" , prefix_str, linebuf); |
421 | break; |
422 | } |
423 | if (ret) |
424 | return ret; |
425 | } |
426 | return 0; |
427 | } |
428 | |