1 /* 2 * linux/fs/seq_file.c 3 * 4 * helper functions for making synthetic files from sequences of records. 5 * initial implementation -- AV, Oct 2001. 6 */ 7 8 #include <linux/fs.h> 9 #include <linux/module.h> 10 #include <linux/seq_file.h> 11 #include <linux/slab.h> 12 13 #include <asm/uaccess.h> 14 #include <asm/page.h> 15 16 /** 17 * seq_open - initialize sequential file 18 * @file: file we initialize 19 * @op: method table describing the sequence 20 * 21 * seq_open() sets @file, associating it with a sequence described 22 * by @op. @op->start() sets the iterator up and returns the first 23 * element of sequence. @op->stop() shuts it down. @op->next() 24 * returns the next element of sequence. @op->show() prints element 25 * into the buffer. In case of error ->start() and ->next() return 26 * ERR_PTR(error). In the end of sequence they return %NULL. ->show() 27 * returns 0 in case of success and negative number in case of error. 28 */ 29 int seq_open(struct file *file, const struct seq_operations *op) 30 { 31 struct seq_file *p = file->private_data; 32 33 if (!p) { 34 p = kmalloc(sizeof(*p), GFP_KERNEL); 35 if (!p) 36 return -ENOMEM; 37 file->private_data = p; 38 } 39 memset(p, 0, sizeof(*p)); 40 mutex_init(&p->lock); 41 p->op = op; 42 43 /* 44 * Wrappers around seq_open(e.g. swaps_open) need to be 45 * aware of this. If they set f_version themselves, they 46 * should call seq_open first and then set f_version. 47 */ 48 file->f_version = 0; 49 50 /* SEQ files support lseek, but not pread/pwrite */ 51 file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); 52 return 0; 53 } 54 EXPORT_SYMBOL(seq_open); 55 56 /** 57 * seq_read - ->read() method for sequential files. 58 * @file: the file to read from 59 * @buf: the buffer to read to 60 * @size: the maximum number of bytes to read 61 * @ppos: the current position in the file 62 * 63 * Ready-made ->f_op->read() 64 */ 65 ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) 66 { 67 struct seq_file *m = (struct seq_file *)file->private_data; 68 size_t copied = 0; 69 loff_t pos; 70 size_t n; 71 void *p; 72 int err = 0; 73 74 mutex_lock(&m->lock); 75 /* 76 * seq_file->op->..m_start/m_stop/m_next may do special actions 77 * or optimisations based on the file->f_version, so we want to 78 * pass the file->f_version to those methods. 79 * 80 * seq_file->version is just copy of f_version, and seq_file 81 * methods can treat it simply as file version. 82 * It is copied in first and copied out after all operations. 83 * It is convenient to have it as part of structure to avoid the 84 * need of passing another argument to all the seq_file methods. 85 */ 86 m->version = file->f_version; 87 /* grab buffer if we didn't have one */ 88 if (!m->buf) { 89 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); 90 if (!m->buf) 91 goto Enomem; 92 } 93 /* if not empty - flush it first */ 94 if (m->count) { 95 n = min(m->count, size); 96 err = copy_to_user(buf, m->buf + m->from, n); 97 if (err) 98 goto Efault; 99 m->count -= n; 100 m->from += n; 101 size -= n; 102 buf += n; 103 copied += n; 104 if (!m->count) 105 m->index++; 106 if (!size) 107 goto Done; 108 } 109 /* we need at least one record in buffer */ 110 while (1) { 111 pos = m->index; 112 p = m->op->start(m, &pos); 113 err = PTR_ERR(p); 114 if (!p || IS_ERR(p)) 115 break; 116 err = m->op->show(m, p); 117 if (err) 118 break; 119 if (m->count < m->size) 120 goto Fill; 121 m->op->stop(m, p); 122 kfree(m->buf); 123 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); 124 if (!m->buf) 125 goto Enomem; 126 m->count = 0; 127 m->version = 0; 128 } 129 m->op->stop(m, p); 130 m->count = 0; 131 goto Done; 132 Fill: 133 /* they want more? let's try to get some more */ 134 while (m->count < size) { 135 size_t offs = m->count; 136 loff_t next = pos; 137 p = m->op->next(m, p, &next); 138 if (!p || IS_ERR(p)) { 139 err = PTR_ERR(p); 140 break; 141 } 142 err = m->op->show(m, p); 143 if (err || m->count == m->size) { 144 m->count = offs; 145 break; 146 } 147 pos = next; 148 } 149 m->op->stop(m, p); 150 n = min(m->count, size); 151 err = copy_to_user(buf, m->buf, n); 152 if (err) 153 goto Efault; 154 copied += n; 155 m->count -= n; 156 if (m->count) 157 m->from = n; 158 else 159 pos++; 160 m->index = pos; 161 Done: 162 if (!copied) 163 copied = err; 164 else 165 *ppos += copied; 166 file->f_version = m->version; 167 mutex_unlock(&m->lock); 168 return copied; 169 Enomem: 170 err = -ENOMEM; 171 goto Done; 172 Efault: 173 err = -EFAULT; 174 goto Done; 175 } 176 EXPORT_SYMBOL(seq_read); 177 178 static int traverse(struct seq_file *m, loff_t offset) 179 { 180 loff_t pos = 0, index; 181 int error = 0; 182 void *p; 183 184 m->version = 0; 185 index = 0; 186 m->count = m->from = 0; 187 if (!offset) { 188 m->index = index; 189 return 0; 190 } 191 if (!m->buf) { 192 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); 193 if (!m->buf) 194 return -ENOMEM; 195 } 196 p = m->op->start(m, &index); 197 while (p) { 198 error = PTR_ERR(p); 199 if (IS_ERR(p)) 200 break; 201 error = m->op->show(m, p); 202 if (error) 203 break; 204 if (m->count == m->size) 205 goto Eoverflow; 206 if (pos + m->count > offset) { 207 m->from = offset - pos; 208 m->count -= m->from; 209 m->index = index; 210 break; 211 } 212 pos += m->count; 213 m->count = 0; 214 if (pos == offset) { 215 index++; 216 m->index = index; 217 break; 218 } 219 p = m->op->next(m, p, &index); 220 } 221 m->op->stop(m, p); 222 return error; 223 224 Eoverflow: 225 m->op->stop(m, p); 226 kfree(m->buf); 227 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); 228 return !m->buf ? -ENOMEM : -EAGAIN; 229 } 230 231 /** 232 * seq_lseek - ->llseek() method for sequential files. 233 * @file: the file in question 234 * @offset: new position 235 * @origin: 0 for absolute, 1 for relative position 236 * 237 * Ready-made ->f_op->llseek() 238 */ 239 loff_t seq_lseek(struct file *file, loff_t offset, int origin) 240 { 241 struct seq_file *m = (struct seq_file *)file->private_data; 242 long long retval = -EINVAL; 243 244 mutex_lock(&m->lock); 245 m->version = file->f_version; 246 switch (origin) { 247 case 1: 248 offset += file->f_pos; 249 case 0: 250 if (offset < 0) 251 break; 252 retval = offset; 253 if (offset != file->f_pos) { 254 while ((retval=traverse(m, offset)) == -EAGAIN) 255 ; 256 if (retval) { 257 /* with extreme prejudice... */ 258 file->f_pos = 0; 259 m->version = 0; 260 m->index = 0; 261 m->count = 0; 262 } else { 263 retval = file->f_pos = offset; 264 } 265 } 266 } 267 file->f_version = m->version; 268 mutex_unlock(&m->lock); 269 return retval; 270 } 271 EXPORT_SYMBOL(seq_lseek); 272 273 /** 274 * seq_release - free the structures associated with sequential file. 275 * @file: file in question 276 * @inode: file->f_path.dentry->d_inode 277 * 278 * Frees the structures associated with sequential file; can be used 279 * as ->f_op->release() if you don't have private data to destroy. 280 */ 281 int seq_release(struct inode *inode, struct file *file) 282 { 283 struct seq_file *m = (struct seq_file *)file->private_data; 284 kfree(m->buf); 285 kfree(m); 286 return 0; 287 } 288 EXPORT_SYMBOL(seq_release); 289 290 /** 291 * seq_escape - print string into buffer, escaping some characters 292 * @m: target buffer 293 * @s: string 294 * @esc: set of characters that need escaping 295 * 296 * Puts string into buffer, replacing each occurrence of character from 297 * @esc with usual octal escape. Returns 0 in case of success, -1 - in 298 * case of overflow. 299 */ 300 int seq_escape(struct seq_file *m, const char *s, const char *esc) 301 { 302 char *end = m->buf + m->size; 303 char *p; 304 char c; 305 306 for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { 307 if (!strchr(esc, c)) { 308 *p++ = c; 309 continue; 310 } 311 if (p + 3 < end) { 312 *p++ = '\\'; 313 *p++ = '0' + ((c & 0300) >> 6); 314 *p++ = '0' + ((c & 070) >> 3); 315 *p++ = '0' + (c & 07); 316 continue; 317 } 318 m->count = m->size; 319 return -1; 320 } 321 m->count = p - m->buf; 322 return 0; 323 } 324 EXPORT_SYMBOL(seq_escape); 325 326 int seq_printf(struct seq_file *m, const char *f, ...) 327 { 328 va_list args; 329 int len; 330 331 if (m->count < m->size) { 332 va_start(args, f); 333 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); 334 va_end(args); 335 if (m->count + len < m->size) { 336 m->count += len; 337 return 0; 338 } 339 } 340 m->count = m->size; 341 return -1; 342 } 343 EXPORT_SYMBOL(seq_printf); 344 345 int seq_path(struct seq_file *m, struct path *path, char *esc) 346 { 347 if (m->count < m->size) { 348 char *s = m->buf + m->count; 349 char *p = d_path(path, s, m->size - m->count); 350 if (!IS_ERR(p)) { 351 while (s <= p) { 352 char c = *p++; 353 if (!c) { 354 p = m->buf + m->count; 355 m->count = s - m->buf; 356 return s - p; 357 } else if (!strchr(esc, c)) { 358 *s++ = c; 359 } else if (s + 4 > p) { 360 break; 361 } else { 362 *s++ = '\\'; 363 *s++ = '0' + ((c & 0300) >> 6); 364 *s++ = '0' + ((c & 070) >> 3); 365 *s++ = '0' + (c & 07); 366 } 367 } 368 } 369 } 370 m->count = m->size; 371 return -1; 372 } 373 EXPORT_SYMBOL(seq_path); 374 375 static void *single_start(struct seq_file *p, loff_t *pos) 376 { 377 return NULL + (*pos == 0); 378 } 379 380 static void *single_next(struct seq_file *p, void *v, loff_t *pos) 381 { 382 ++*pos; 383 return NULL; 384 } 385 386 static void single_stop(struct seq_file *p, void *v) 387 { 388 } 389 390 int single_open(struct file *file, int (*show)(struct seq_file *, void *), 391 void *data) 392 { 393 struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL); 394 int res = -ENOMEM; 395 396 if (op) { 397 op->start = single_start; 398 op->next = single_next; 399 op->stop = single_stop; 400 op->show = show; 401 res = seq_open(file, op); 402 if (!res) 403 ((struct seq_file *)file->private_data)->private = data; 404 else 405 kfree(op); 406 } 407 return res; 408 } 409 EXPORT_SYMBOL(single_open); 410 411 int single_release(struct inode *inode, struct file *file) 412 { 413 const struct seq_operations *op = ((struct seq_file *)file->private_data)->op; 414 int res = seq_release(inode, file); 415 kfree(op); 416 return res; 417 } 418 EXPORT_SYMBOL(single_release); 419 420 int seq_release_private(struct inode *inode, struct file *file) 421 { 422 struct seq_file *seq = file->private_data; 423 424 kfree(seq->private); 425 seq->private = NULL; 426 return seq_release(inode, file); 427 } 428 EXPORT_SYMBOL(seq_release_private); 429 430 void *__seq_open_private(struct file *f, const struct seq_operations *ops, 431 int psize) 432 { 433 int rc; 434 void *private; 435 struct seq_file *seq; 436 437 private = kzalloc(psize, GFP_KERNEL); 438 if (private == NULL) 439 goto out; 440 441 rc = seq_open(f, ops); 442 if (rc < 0) 443 goto out_free; 444 445 seq = f->private_data; 446 seq->private = private; 447 return private; 448 449 out_free: 450 kfree(private); 451 out: 452 return NULL; 453 } 454 EXPORT_SYMBOL(__seq_open_private); 455 456 int seq_open_private(struct file *filp, const struct seq_operations *ops, 457 int psize) 458 { 459 return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM; 460 } 461 EXPORT_SYMBOL(seq_open_private); 462 463 int seq_putc(struct seq_file *m, char c) 464 { 465 if (m->count < m->size) { 466 m->buf[m->count++] = c; 467 return 0; 468 } 469 return -1; 470 } 471 EXPORT_SYMBOL(seq_putc); 472 473 int seq_puts(struct seq_file *m, const char *s) 474 { 475 int len = strlen(s); 476 if (m->count + len < m->size) { 477 memcpy(m->buf + m->count, s, len); 478 m->count += len; 479 return 0; 480 } 481 m->count = m->size; 482 return -1; 483 } 484 EXPORT_SYMBOL(seq_puts); 485 486 struct list_head *seq_list_start(struct list_head *head, loff_t pos) 487 { 488 struct list_head *lh; 489 490 list_for_each(lh, head) 491 if (pos-- == 0) 492 return lh; 493 494 return NULL; 495 } 496 497 EXPORT_SYMBOL(seq_list_start); 498 499 struct list_head *seq_list_start_head(struct list_head *head, loff_t pos) 500 { 501 if (!pos) 502 return head; 503 504 return seq_list_start(head, pos - 1); 505 } 506 507 EXPORT_SYMBOL(seq_list_start_head); 508 509 struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) 510 { 511 struct list_head *lh; 512 513 lh = ((struct list_head *)v)->next; 514 ++*ppos; 515 return lh == head ? NULL : lh; 516 } 517 518 EXPORT_SYMBOL(seq_list_next); 519