1 /* 2 * seq_buf.c 3 * 4 * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 5 * 6 * The seq_buf is a handy tool that allows you to pass a descriptor around 7 * to a buffer that other functions can write to. It is similar to the 8 * seq_file functionality but has some differences. 9 * 10 * To use it, the seq_buf must be initialized with seq_buf_init(). 11 * This will set up the counters within the descriptor. You can call 12 * seq_buf_init() more than once to reset the seq_buf to start 13 * from scratch. 14 */ 15 #include <linux/uaccess.h> 16 #include <linux/seq_file.h> 17 #include <linux/seq_buf.h> 18 19 /** 20 * seq_buf_can_fit - can the new data fit in the current buffer? 21 * @s: the seq_buf descriptor 22 * @len: The length to see if it can fit in the current buffer 23 * 24 * Returns true if there's enough unused space in the seq_buf buffer 25 * to fit the amount of new data according to @len. 26 */ 27 static bool seq_buf_can_fit(struct seq_buf *s, size_t len) 28 { 29 return s->len + len <= s->size; 30 } 31 32 /** 33 * seq_buf_print_seq - move the contents of seq_buf into a seq_file 34 * @m: the seq_file descriptor that is the destination 35 * @s: the seq_buf descriptor that is the source. 36 * 37 * Returns zero on success, non zero otherwise 38 */ 39 int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) 40 { 41 unsigned int len = seq_buf_used(s); 42 43 return seq_write(m, s->buffer, len); 44 } 45 46 /** 47 * seq_buf_vprintf - sequence printing of information. 48 * @s: seq_buf descriptor 49 * @fmt: printf format string 50 * @args: va_list of arguments from a printf() type function 51 * 52 * Writes a vnprintf() format into the sequencce buffer. 53 * 54 * Returns zero on success, -1 on overflow. 55 */ 56 int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) 57 { 58 int len; 59 60 WARN_ON(s->size == 0); 61 62 if (s->len < s->size) { 63 len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args); 64 if (s->len + len < s->size) { 65 s->len += len; 66 return 0; 67 } 68 } 69 seq_buf_set_overflow(s); 70 return -1; 71 } 72 73 /** 74 * seq_buf_printf - sequence printing of information 75 * @s: seq_buf descriptor 76 * @fmt: printf format string 77 * 78 * Writes a printf() format into the sequence buffer. 79 * 80 * Returns zero on success, -1 on overflow. 81 */ 82 int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) 83 { 84 va_list ap; 85 int ret; 86 87 va_start(ap, fmt); 88 ret = seq_buf_vprintf(s, fmt, ap); 89 va_end(ap); 90 91 return ret; 92 } 93 94 #ifdef CONFIG_BINARY_PRINTF 95 /** 96 * seq_buf_bprintf - Write the printf string from binary arguments 97 * @s: seq_buf descriptor 98 * @fmt: The format string for the @binary arguments 99 * @binary: The binary arguments for @fmt. 100 * 101 * When recording in a fast path, a printf may be recorded with just 102 * saving the format and the arguments as they were passed to the 103 * function, instead of wasting cycles converting the arguments into 104 * ASCII characters. Instead, the arguments are saved in a 32 bit 105 * word array that is defined by the format string constraints. 106 * 107 * This function will take the format and the binary array and finish 108 * the conversion into the ASCII string within the buffer. 109 * 110 * Returns zero on success, -1 on overflow. 111 */ 112 int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) 113 { 114 unsigned int len = seq_buf_buffer_left(s); 115 int ret; 116 117 WARN_ON(s->size == 0); 118 119 if (s->len < s->size) { 120 ret = bstr_printf(s->buffer + s->len, len, fmt, binary); 121 if (s->len + ret < s->size) { 122 s->len += ret; 123 return 0; 124 } 125 } 126 seq_buf_set_overflow(s); 127 return -1; 128 } 129 #endif /* CONFIG_BINARY_PRINTF */ 130 131 /** 132 * seq_buf_puts - sequence printing of simple string 133 * @s: seq_buf descriptor 134 * @str: simple string to record 135 * 136 * Copy a simple string into the sequence buffer. 137 * 138 * Returns zero on success, -1 on overflow 139 */ 140 int seq_buf_puts(struct seq_buf *s, const char *str) 141 { 142 unsigned int len = strlen(str); 143 144 WARN_ON(s->size == 0); 145 146 if (seq_buf_can_fit(s, len)) { 147 memcpy(s->buffer + s->len, str, len); 148 s->len += len; 149 return 0; 150 } 151 seq_buf_set_overflow(s); 152 return -1; 153 } 154 155 /** 156 * seq_buf_putc - sequence printing of simple character 157 * @s: seq_buf descriptor 158 * @c: simple character to record 159 * 160 * Copy a single character into the sequence buffer. 161 * 162 * Returns zero on success, -1 on overflow 163 */ 164 int seq_buf_putc(struct seq_buf *s, unsigned char c) 165 { 166 WARN_ON(s->size == 0); 167 168 if (seq_buf_can_fit(s, 1)) { 169 s->buffer[s->len++] = c; 170 return 0; 171 } 172 seq_buf_set_overflow(s); 173 return -1; 174 } 175 176 /** 177 * seq_buf_putmem - write raw data into the sequenc buffer 178 * @s: seq_buf descriptor 179 * @mem: The raw memory to copy into the buffer 180 * @len: The length of the raw memory to copy (in bytes) 181 * 182 * There may be cases where raw memory needs to be written into the 183 * buffer and a strcpy() would not work. Using this function allows 184 * for such cases. 185 * 186 * Returns zero on success, -1 on overflow 187 */ 188 int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) 189 { 190 WARN_ON(s->size == 0); 191 192 if (seq_buf_can_fit(s, len)) { 193 memcpy(s->buffer + s->len, mem, len); 194 s->len += len; 195 return 0; 196 } 197 seq_buf_set_overflow(s); 198 return -1; 199 } 200 201 #define MAX_MEMHEX_BYTES 8U 202 #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) 203 204 /** 205 * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex 206 * @s: seq_buf descriptor 207 * @mem: The raw memory to write its hex ASCII representation of 208 * @len: The length of the raw memory to copy (in bytes) 209 * 210 * This is similar to seq_buf_putmem() except instead of just copying the 211 * raw memory into the buffer it writes its ASCII representation of it 212 * in hex characters. 213 * 214 * Returns zero on success, -1 on overflow 215 */ 216 int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, 217 unsigned int len) 218 { 219 unsigned char hex[HEX_CHARS]; 220 const unsigned char *data = mem; 221 unsigned int start_len; 222 int i, j; 223 224 WARN_ON(s->size == 0); 225 226 while (len) { 227 start_len = min(len, HEX_CHARS - 1); 228 #ifdef __BIG_ENDIAN 229 for (i = 0, j = 0; i < start_len; i++) { 230 #else 231 for (i = start_len-1, j = 0; i >= 0; i--) { 232 #endif 233 hex[j++] = hex_asc_hi(data[i]); 234 hex[j++] = hex_asc_lo(data[i]); 235 } 236 if (WARN_ON_ONCE(j == 0 || j/2 > len)) 237 break; 238 239 /* j increments twice per loop */ 240 len -= j / 2; 241 hex[j++] = ' '; 242 243 seq_buf_putmem(s, hex, j); 244 if (seq_buf_has_overflowed(s)) 245 return -1; 246 } 247 return 0; 248 } 249 250 /** 251 * seq_buf_path - copy a path into the sequence buffer 252 * @s: seq_buf descriptor 253 * @path: path to write into the sequence buffer. 254 * @esc: set of characters to escape in the output 255 * 256 * Write a path name into the sequence buffer. 257 * 258 * Returns the number of written bytes on success, -1 on overflow 259 */ 260 int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) 261 { 262 char *buf; 263 size_t size = seq_buf_get_buf(s, &buf); 264 int res = -1; 265 266 WARN_ON(s->size == 0); 267 268 if (size) { 269 char *p = d_path(path, buf, size); 270 if (!IS_ERR(p)) { 271 char *end = mangle_path(buf, p, esc); 272 if (end) 273 res = end - buf; 274 } 275 } 276 seq_buf_commit(s, res); 277 278 return res; 279 } 280 281 /** 282 * seq_buf_to_user - copy the squence buffer to user space 283 * @s: seq_buf descriptor 284 * @ubuf: The userspace memory location to copy to 285 * @cnt: The amount to copy 286 * 287 * Copies the sequence buffer into the userspace memory pointed to 288 * by @ubuf. It starts from the last read position (@s->readpos) 289 * and writes up to @cnt characters or till it reaches the end of 290 * the content in the buffer (@s->len), which ever comes first. 291 * 292 * On success, it returns a positive number of the number of bytes 293 * it copied. 294 * 295 * On failure it returns -EBUSY if all of the content in the 296 * sequence has been already read, which includes nothing in the 297 * sequence (@s->len == @s->readpos). 298 * 299 * Returns -EFAULT if the copy to userspace fails. 300 */ 301 int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt) 302 { 303 int len; 304 int ret; 305 306 if (!cnt) 307 return 0; 308 309 len = seq_buf_used(s); 310 311 if (len <= s->readpos) 312 return -EBUSY; 313 314 len -= s->readpos; 315 if (cnt > len) 316 cnt = len; 317 ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); 318 if (ret == cnt) 319 return -EFAULT; 320 321 cnt -= ret; 322 323 s->readpos += cnt; 324 return cnt; 325 } 326