linux/lib/seq_buf.c
<<
>>
Prefs
   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 */
  28static 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 */
  40int 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(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 */
  57int 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(s->buffer + s->len, 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 */
  83int 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, ap);
  90        va_end(ap);
  91
  92        return ret;
  93}
  94EXPORT_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 */
 114int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
 115{
 116        unsigned int len = seq_buf_buffer_left(s);
 117        int ret;
 118
 119        WARN_ON(s->size == 0);
 120
 121        if (s->len < s->size) {
 122                ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
 123                if (s->len + ret < s->size) {
 124                        s->len += ret;
 125                        return 0;
 126                }
 127        }
 128        seq_buf_set_overflow(s);
 129        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 */
 142int seq_buf_puts(struct seq_buf *s, const char *str)
 143{
 144        size_t len = strlen(str);
 145
 146        WARN_ON(s->size == 0);
 147
 148        /* Add 1 to len for the trailing null byte which must be there */
 149        len += 1;
 150
 151        if (seq_buf_can_fit(s, len)) {
 152                memcpy(s->buffer + s->len, str, len);
 153                /* Don't count the trailing null byte against the capacity */
 154                s->len += len - 1;
 155                return 0;
 156        }
 157        seq_buf_set_overflow(s);
 158        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 */
 170int seq_buf_putc(struct seq_buf *s, unsigned char c)
 171{
 172        WARN_ON(s->size == 0);
 173
 174        if (seq_buf_can_fit(s, 1)) {
 175                s->buffer[s->len++] = c;
 176                return 0;
 177        }
 178        seq_buf_set_overflow(s);
 179        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 */
 194int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
 195{
 196        WARN_ON(s->size == 0);
 197
 198        if (seq_buf_can_fit(s, len)) {
 199                memcpy(s->buffer + s->len, mem, len);
 200                s->len += len;
 201                return 0;
 202        }
 203        seq_buf_set_overflow(s);
 204        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 */
 222int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
 223                       unsigned int len)
 224{
 225        unsigned char hex[HEX_CHARS];
 226        const unsigned char *data = mem;
 227        unsigned int start_len;
 228        int i, j;
 229
 230        WARN_ON(s->size == 0);
 231
 232        BUILD_BUG_ON(MAX_MEMHEX_BYTES * 2 >= HEX_CHARS);
 233
 234        while (len) {
 235                start_len = min(len, MAX_MEMHEX_BYTES);
 236#ifdef __BIG_ENDIAN
 237                for (i = 0, j = 0; i < start_len; i++) {
 238#else
 239                for (i = start_len-1, j = 0; i >= 0; i--) {
 240#endif
 241                        hex[j++] = hex_asc_hi(data[i]);
 242                        hex[j++] = hex_asc_lo(data[i]);
 243                }
 244                if (WARN_ON_ONCE(j == 0 || j/2 > len))
 245                        break;
 246
 247                /* j increments twice per loop */
 248                hex[j++] = ' ';
 249
 250                seq_buf_putmem(s, hex, j);
 251                if (seq_buf_has_overflowed(s))
 252                        return -1;
 253
 254                len -= start_len;
 255                data += start_len;
 256        }
 257        return 0;
 258}
 259
 260/**
 261 * seq_buf_path - copy a path into the sequence buffer
 262 * @s: seq_buf descriptor
 263 * @path: path to write into the sequence buffer.
 264 * @esc: set of characters to escape in the output
 265 *
 266 * Write a path name into the sequence buffer.
 267 *
 268 * Returns the number of written bytes on success, -1 on overflow
 269 */
 270int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
 271{
 272        char *buf;
 273        size_t size = seq_buf_get_buf(s, &buf);
 274        int res = -1;
 275
 276        WARN_ON(s->size == 0);
 277
 278        if (size) {
 279                char *p = d_path(path, buf, size);
 280                if (!IS_ERR(p)) {
 281                        char *end = mangle_path(buf, p, esc);
 282                        if (end)
 283                                res = end - buf;
 284                }
 285        }
 286        seq_buf_commit(s, res);
 287
 288        return res;
 289}
 290
 291/**
 292 * seq_buf_to_user - copy the sequence buffer to user space
 293 * @s: seq_buf descriptor
 294 * @ubuf: The userspace memory location to copy to
 295 * @cnt: The amount to copy
 296 *
 297 * Copies the sequence buffer into the userspace memory pointed to
 298 * by @ubuf. It starts from the last read position (@s->readpos)
 299 * and writes up to @cnt characters or till it reaches the end of
 300 * the content in the buffer (@s->len), which ever comes first.
 301 *
 302 * On success, it returns a positive number of the number of bytes
 303 * it copied.
 304 *
 305 * On failure it returns -EBUSY if all of the content in the
 306 * sequence has been already read, which includes nothing in the
 307 * sequence (@s->len == @s->readpos).
 308 *
 309 * Returns -EFAULT if the copy to userspace fails.
 310 */
 311int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt)
 312{
 313        int len;
 314        int ret;
 315
 316        if (!cnt)
 317                return 0;
 318
 319        len = seq_buf_used(s);
 320
 321        if (len <= s->readpos)
 322                return -EBUSY;
 323
 324        len -= s->readpos;
 325        if (cnt > len)
 326                cnt = len;
 327        ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
 328        if (ret == cnt)
 329                return -EFAULT;
 330
 331        cnt -= ret;
 332
 333        s->readpos += cnt;
 334        return cnt;
 335}
 336
 337/**
 338 * seq_buf_hex_dump - print formatted hex dump into the sequence buffer
 339 * @s: seq_buf descriptor
 340 * @prefix_str: string to prefix each line with;
 341 *  caller supplies trailing spaces for alignment if desired
 342 * @prefix_type: controls whether prefix of an offset, address, or none
 343 *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
 344 * @rowsize: number of bytes to print per line; must be 16 or 32
 345 * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
 346 * @buf: data blob to dump
 347 * @len: number of bytes in the @buf
 348 * @ascii: include ASCII after the hex output
 349 *
 350 * Function is an analogue of print_hex_dump() and thus has similar interface.
 351 *
 352 * linebuf size is maximal length for one line.
 353 * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for
 354 *      separating space
 355 * 2 - spaces separating hex dump and ascii representation
 356 * 32 - ascii representation
 357 * 1 - terminating '\0'
 358 *
 359 * Returns zero on success, -1 on overflow
 360 */
 361int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type,
 362                     int rowsize, int groupsize,
 363                     const void *buf, size_t len, bool ascii)
 364{
 365        const u8 *ptr = buf;
 366        int i, linelen, remaining = len;
 367        unsigned char linebuf[32 * 3 + 2 + 32 + 1];
 368        int ret;
 369
 370        if (rowsize != 16 && rowsize != 32)
 371                rowsize = 16;
 372
 373        for (i = 0; i < len; i += rowsize) {
 374                linelen = min(remaining, rowsize);
 375                remaining -= rowsize;
 376
 377                hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
 378                                   linebuf, sizeof(linebuf), ascii);
 379
 380                switch (prefix_type) {
 381                case DUMP_PREFIX_ADDRESS:
 382                        ret = seq_buf_printf(s, "%s%p: %s\n",
 383                               prefix_str, ptr + i, linebuf);
 384                        break;
 385                case DUMP_PREFIX_OFFSET:
 386                        ret = seq_buf_printf(s, "%s%.8x: %s\n",
 387                                             prefix_str, i, linebuf);
 388                        break;
 389                default:
 390                        ret = seq_buf_printf(s, "%s%s\n", prefix_str, linebuf);
 391                        break;
 392                }
 393                if (ret)
 394                        return ret;
 395        }
 396        return 0;
 397}
 398