Line data Source code
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 0 : static bool seq_buf_can_fit(struct seq_buf *s, size_t len)
29 : {
30 0 : 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 0 : int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
41 : {
42 0 : unsigned int len = seq_buf_used(s);
43 :
44 0 : return seq_write(m, 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 0 : int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
58 : {
59 0 : int len;
60 :
61 0 : WARN_ON(s->size == 0);
62 :
63 0 : if (s->len < s->size) {
64 0 : len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
65 0 : if (s->len + len < s->size) {
66 0 : s->len += len;
67 0 : return 0;
68 : }
69 : }
70 0 : seq_buf_set_overflow(s);
71 0 : 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 0 : int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
84 : {
85 0 : va_list ap;
86 0 : int ret;
87 :
88 0 : va_start(ap, fmt);
89 0 : ret = seq_buf_vprintf(s, fmt, ap);
90 0 : va_end(ap);
91 :
92 0 : return ret;
93 : }
94 : EXPORT_SYMBOL_GPL(seq_buf_printf);
95 :
96 : #ifdef CONFIG_BINARY_PRINTF
97 : /**
98 : * seq_buf_bprintf - Write the printf string from binary arguments
99 : * @s: seq_buf descriptor
100 : * @fmt: The format string for the @binary arguments
101 : * @binary: The binary arguments for @fmt.
102 : *
103 : * When recording in a fast path, a printf may be recorded with just
104 : * saving the format and the arguments as they were passed to the
105 : * function, instead of wasting cycles converting the arguments into
106 : * ASCII characters. Instead, the arguments are saved in a 32 bit
107 : * word array that is defined by the format string constraints.
108 : *
109 : * This function will take the format and the binary array and finish
110 : * the conversion into the ASCII string within the buffer.
111 : *
112 : * Returns zero on success, -1 on overflow.
113 : */
114 0 : int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
115 : {
116 0 : unsigned int len = seq_buf_buffer_left(s);
117 0 : int ret;
118 :
119 0 : WARN_ON(s->size == 0);
120 :
121 0 : if (s->len < s->size) {
122 0 : ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
123 0 : if (s->len + ret < s->size) {
124 0 : s->len += ret;
125 0 : return 0;
126 : }
127 : }
128 0 : seq_buf_set_overflow(s);
129 0 : return -1;
130 : }
131 : #endif /* CONFIG_BINARY_PRINTF */
132 :
133 : /**
134 : * seq_buf_puts - sequence printing of simple string
135 : * @s: seq_buf descriptor
136 : * @str: simple string to record
137 : *
138 : * Copy a simple string into the sequence buffer.
139 : *
140 : * Returns zero on success, -1 on overflow
141 : */
142 0 : int seq_buf_puts(struct seq_buf *s, const char *str)
143 : {
144 0 : size_t len = strlen(str);
145 :
146 0 : WARN_ON(s->size == 0);
147 :
148 : /* Add 1 to len for the trailing null byte which must be there */
149 0 : len += 1;
150 :
151 0 : if (seq_buf_can_fit(s, len)) {
152 0 : memcpy(s->buffer + s->len, str, len);
153 : /* Don't count the trailing null byte against the capacity */
154 0 : s->len += len - 1;
155 0 : return 0;
156 : }
157 0 : seq_buf_set_overflow(s);
158 0 : return -1;
159 : }
160 :
161 : /**
162 : * seq_buf_putc - sequence printing of simple character
163 : * @s: seq_buf descriptor
164 : * @c: simple character to record
165 : *
166 : * Copy a single character into the sequence buffer.
167 : *
168 : * Returns zero on success, -1 on overflow
169 : */
170 0 : int seq_buf_putc(struct seq_buf *s, unsigned char c)
171 : {
172 0 : WARN_ON(s->size == 0);
173 :
174 0 : if (seq_buf_can_fit(s, 1)) {
175 0 : s->buffer[s->len++] = c;
176 0 : return 0;
177 : }
178 0 : seq_buf_set_overflow(s);
179 0 : return -1;
180 : }
181 :
182 : /**
183 : * seq_buf_putmem - write raw data into the sequenc buffer
184 : * @s: seq_buf descriptor
185 : * @mem: The raw memory to copy into the buffer
186 : * @len: The length of the raw memory to copy (in bytes)
187 : *
188 : * There may be cases where raw memory needs to be written into the
189 : * buffer and a strcpy() would not work. Using this function allows
190 : * for such cases.
191 : *
192 : * Returns zero on success, -1 on overflow
193 : */
194 0 : int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
195 : {
196 0 : WARN_ON(s->size == 0);
197 :
198 0 : if (seq_buf_can_fit(s, len)) {
199 0 : memcpy(s->buffer + s->len, mem, len);
200 0 : s->len += len;
201 0 : return 0;
202 : }
203 0 : seq_buf_set_overflow(s);
204 0 : return -1;
205 : }
206 :
207 : #define MAX_MEMHEX_BYTES 8U
208 : #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
209 :
210 : /**
211 : * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex
212 : * @s: seq_buf descriptor
213 : * @mem: The raw memory to write its hex ASCII representation of
214 : * @len: The length of the raw memory to copy (in bytes)
215 : *
216 : * This is similar to seq_buf_putmem() except instead of just copying the
217 : * raw memory into the buffer it writes its ASCII representation of it
218 : * in hex characters.
219 : *
220 : * Returns zero on success, -1 on overflow
221 : */
222 0 : int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
223 : unsigned int len)
224 : {
225 0 : unsigned char hex[HEX_CHARS];
226 0 : const unsigned char *data = mem;
227 0 : unsigned int start_len;
228 0 : int i, j;
229 :
230 0 : WARN_ON(s->size == 0);
231 :
232 0 : while (len) {
233 0 : start_len = min(len, HEX_CHARS - 1);
234 : #ifdef __BIG_ENDIAN
235 : for (i = 0, j = 0; i < start_len; i++) {
236 : #else
237 0 : for (i = start_len-1, j = 0; i >= 0; i--) {
238 : #endif
239 0 : hex[j++] = hex_asc_hi(data[i]);
240 0 : hex[j++] = hex_asc_lo(data[i]);
241 : }
242 0 : if (WARN_ON_ONCE(j == 0 || j/2 > len))
243 : break;
244 :
245 : /* j increments twice per loop */
246 0 : len -= j / 2;
247 0 : hex[j++] = ' ';
248 :
249 0 : seq_buf_putmem(s, hex, j);
250 0 : if (seq_buf_has_overflowed(s))
251 : return -1;
252 : }
253 : return 0;
254 : }
255 :
256 : /**
257 : * seq_buf_path - copy a path into the sequence buffer
258 : * @s: seq_buf descriptor
259 : * @path: path to write into the sequence buffer.
260 : * @esc: set of characters to escape in the output
261 : *
262 : * Write a path name into the sequence buffer.
263 : *
264 : * Returns the number of written bytes on success, -1 on overflow
265 : */
266 0 : int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
267 : {
268 0 : char *buf;
269 0 : size_t size = seq_buf_get_buf(s, &buf);
270 0 : int res = -1;
271 :
272 0 : WARN_ON(s->size == 0);
273 :
274 0 : if (size) {
275 0 : char *p = d_path(path, buf, size);
276 0 : if (!IS_ERR(p)) {
277 0 : char *end = mangle_path(buf, p, esc);
278 0 : if (end)
279 0 : res = end - buf;
280 : }
281 : }
282 0 : seq_buf_commit(s, res);
283 :
284 0 : return res;
285 : }
286 :
287 : /**
288 : * seq_buf_to_user - copy the squence buffer to user space
289 : * @s: seq_buf descriptor
290 : * @ubuf: The userspace memory location to copy to
291 : * @cnt: The amount to copy
292 : *
293 : * Copies the sequence buffer into the userspace memory pointed to
294 : * by @ubuf. It starts from the last read position (@s->readpos)
295 : * and writes up to @cnt characters or till it reaches the end of
296 : * the content in the buffer (@s->len), which ever comes first.
297 : *
298 : * On success, it returns a positive number of the number of bytes
299 : * it copied.
300 : *
301 : * On failure it returns -EBUSY if all of the content in the
302 : * sequence has been already read, which includes nothing in the
303 : * sequence (@s->len == @s->readpos).
304 : *
305 : * Returns -EFAULT if the copy to userspace fails.
306 : */
307 0 : int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt)
308 : {
309 0 : int len;
310 0 : int ret;
311 :
312 0 : if (!cnt)
313 : return 0;
314 :
315 0 : len = seq_buf_used(s);
316 :
317 0 : if (len <= s->readpos)
318 : return -EBUSY;
319 :
320 0 : len -= s->readpos;
321 0 : if (cnt > len)
322 : cnt = len;
323 0 : ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
324 0 : if (ret == cnt)
325 : return -EFAULT;
326 :
327 0 : cnt -= ret;
328 :
329 0 : s->readpos += cnt;
330 0 : return cnt;
331 : }
332 :
333 : /**
334 : * seq_buf_hex_dump - print formatted hex dump into the sequence buffer
335 : * @s: seq_buf descriptor
336 : * @prefix_str: string to prefix each line with;
337 : * caller supplies trailing spaces for alignment if desired
338 : * @prefix_type: controls whether prefix of an offset, address, or none
339 : * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
340 : * @rowsize: number of bytes to print per line; must be 16 or 32
341 : * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
342 : * @buf: data blob to dump
343 : * @len: number of bytes in the @buf
344 : * @ascii: include ASCII after the hex output
345 : *
346 : * Function is an analogue of print_hex_dump() and thus has similar interface.
347 : *
348 : * linebuf size is maximal length for one line.
349 : * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for
350 : * separating space
351 : * 2 - spaces separating hex dump and ascii representation
352 : * 32 - ascii representation
353 : * 1 - terminating '\0'
354 : *
355 : * Returns zero on success, -1 on overflow
356 : */
357 0 : int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type,
358 : int rowsize, int groupsize,
359 : const void *buf, size_t len, bool ascii)
360 : {
361 0 : const u8 *ptr = buf;
362 0 : int i, linelen, remaining = len;
363 0 : unsigned char linebuf[32 * 3 + 2 + 32 + 1];
364 0 : int ret;
365 :
366 0 : if (rowsize != 16 && rowsize != 32)
367 0 : rowsize = 16;
368 :
369 0 : for (i = 0; i < len; i += rowsize) {
370 0 : linelen = min(remaining, rowsize);
371 0 : remaining -= rowsize;
372 :
373 0 : hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
374 : linebuf, sizeof(linebuf), ascii);
375 :
376 0 : switch (prefix_type) {
377 0 : case DUMP_PREFIX_ADDRESS:
378 0 : ret = seq_buf_printf(s, "%s%p: %s\n",
379 : prefix_str, ptr + i, linebuf);
380 0 : break;
381 0 : case DUMP_PREFIX_OFFSET:
382 0 : ret = seq_buf_printf(s, "%s%.8x: %s\n",
383 : prefix_str, i, linebuf);
384 0 : break;
385 0 : default:
386 0 : ret = seq_buf_printf(s, "%s%s\n", prefix_str, linebuf);
387 0 : break;
388 : }
389 0 : if (ret)
390 0 : return ret;
391 : }
392 : return 0;
393 : }
|