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; 181 int error = 0; 182 void *p; 183 184 m->version = 0; 185 m->index = 0; 186 m->count = m->from = 0; 187 if (!offset) 188 return 0; 189 if (!m->buf) { 190 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); 191 if (!m->buf) 192 return -ENOMEM; 193 } 194 p = m->op->start(m, &m->index); 195 while (p) { 196 error = PTR_ERR(p); 197 if (IS_ERR(p)) 198 break; 199 error = m->op->show(m, p); 200 if (error) 201 break; 202 if (m->count == m->size) 203 goto Eoverflow; 204 if (pos + m->count > offset) { 205 m->from = offset - pos; 206 m->count -= m->from; 207 break; 208 } 209 pos += m->count; 210 m->count = 0; 211 if (pos == offset) { 212 m->index++; 213 break; 214 } 215 p = m->op->next(m, p, &m->index); 216 } 217 m->op->stop(m, p); 218 return error; 219 220 Eoverflow: 221 m->op->stop(m, p); 222 kfree(m->buf); 223 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); 224 return !m->buf ? -ENOMEM : -EAGAIN; 225 } 226 227 /** 228 * seq_lseek - ->llseek() method for sequential files. 229 * @file: the file in question 230 * @offset: new position 231 * @origin: 0 for absolute, 1 for relative position 232 * 233 * Ready-made ->f_op->llseek() 234 */ 235 loff_t seq_lseek(struct file *file, loff_t offset, int origin) 236 { 237 struct seq_file *m = (struct seq_file *)file->private_data; 238 long long retval = -EINVAL; 239 240 mutex_lock(&m->lock); 241 m->version = file->f_version; 242 switch (origin) { 243 case 1: 244 offset += file->f_pos; 245 case 0: 246 if (offset < 0) 247 break; 248 retval = offset; 249 if (offset != file->f_pos) { 250 while ((retval=traverse(m, offset)) == -EAGAIN) 251 ; 252 if (retval) { 253 /* with extreme prejudice... */ 254 file->f_pos = 0; 255 m->version = 0; 256 m->index = 0; 257 m->count = 0; 258 } else { 259 retval = file->f_pos = offset; 260 } 261 } 262 } 263 mutex_unlock(&m->lock); 264 file->f_version = m->version; 265 return retval; 266 } 267 EXPORT_SYMBOL(seq_lseek); 268 269 /** 270 * seq_release - free the structures associated with sequential file. 271 * @file: file in question 272 * @inode: file->f_path.dentry->d_inode 273 * 274 * Frees the structures associated with sequential file; can be used 275 * as ->f_op->release() if you don't have private data to destroy. 276 */ 277 int seq_release(struct inode *inode, struct file *file) 278 { 279 struct seq_file *m = (struct seq_file *)file->private_data; 280 kfree(m->buf); 281 kfree(m); 282 return 0; 283 } 284 EXPORT_SYMBOL(seq_release); 285 286 /** 287 * seq_escape - print string into buffer, escaping some characters 288 * @m: target buffer 289 * @s: string 290 * @esc: set of characters that need escaping 291 * 292 * Puts string into buffer, replacing each occurrence of character from 293 * @esc with usual octal escape. Returns 0 in case of success, -1 - in 294 * case of overflow. 295 */ 296 int seq_escape(struct seq_file *m, const char *s, const char *esc) 297 { 298 char *end = m->buf + m->size; 299 char *p; 300 char c; 301 302 for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { 303 if (!strchr(esc, c)) { 304 *p++ = c; 305 continue; 306 } 307 if (p + 3 < end) { 308 *p++ = '\\'; 309 *p++ = '0' + ((c & 0300) >> 6); 310 *p++ = '0' + ((c & 070) >> 3); 311 *p++ = '0' + (c & 07); 312 continue; 313 } 314 m->count = m->size; 315 return -1; 316 } 317 m->count = p - m->buf; 318 return 0; 319 } 320 EXPORT_SYMBOL(seq_escape); 321 322 int seq_printf(struct seq_file *m, const char *f, ...) 323 { 324 va_list args; 325 int len; 326 327 if (m->count < m->size) { 328 va_start(args, f); 329 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); 330 va_end(args); 331 if (m->count + len < m->size) { 332 m->count += len; 333 return 0; 334 } 335 } 336 m->count = m->size; 337 return -1; 338 } 339 EXPORT_SYMBOL(seq_printf); 340 341 int seq_path(struct seq_file *m, 342 struct vfsmount *mnt, struct dentry *dentry, 343 char *esc) 344 { 345 if (m->count < m->size) { 346 char *s = m->buf + m->count; 347 char *p = d_path(dentry, mnt, s, m->size - m->count); 348 if (!IS_ERR(p)) { 349 while (s <= p) { 350 char c = *p++; 351 if (!c) { 352 p = m->buf + m->count; 353 m->count = s - m->buf; 354 return s - p; 355 } else if (!strchr(esc, c)) { 356 *s++ = c; 357 } else if (s + 4 > p) { 358 break; 359 } else { 360 *s++ = '\\'; 361 *s++ = '0' + ((c & 0300) >> 6); 362 *s++ = '0' + ((c & 070) >> 3); 363 *s++ = '0' + (c & 07); 364 } 365 } 366 } 367 } 368 m->count = m->size; 369 return -1; 370 } 371 EXPORT_SYMBOL(seq_path); 372 373 static void *single_start(struct seq_file *p, loff_t *pos) 374 { 375 return NULL + (*pos == 0); 376 } 377 378 static void *single_next(struct seq_file *p, void *v, loff_t *pos) 379 { 380 ++*pos; 381 return NULL; 382 } 383 384 static void single_stop(struct seq_file *p, void *v) 385 { 386 } 387 388 int single_open(struct file *file, int (*show)(struct seq_file *, void *), 389 void *data) 390 { 391 struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL); 392 int res = -ENOMEM; 393 394 if (op) { 395 op->start = single_start; 396 op->next = single_next; 397 op->stop = single_stop; 398 op->show = show; 399 res = seq_open(file, op); 400 if (!res) 401 ((struct seq_file *)file->private_data)->private = data; 402 else 403 kfree(op); 404 } 405 return res; 406 } 407 EXPORT_SYMBOL(single_open); 408 409 int single_release(struct inode *inode, struct file *file) 410 { 411 const struct seq_operations *op = ((struct seq_file *)file->private_data)->op; 412 int res = seq_release(inode, file); 413 kfree(op); 414 return res; 415 } 416 EXPORT_SYMBOL(single_release); 417 418 int seq_release_private(struct inode *inode, struct file *file) 419 { 420 struct seq_file *seq = file->private_data; 421 422 kfree(seq->private); 423 seq->private = NULL; 424 return seq_release(inode, file); 425 } 426 EXPORT_SYMBOL(seq_release_private); 427 428 int seq_putc(struct seq_file *m, char c) 429 { 430 if (m->count < m->size) { 431 m->buf[m->count++] = c; 432 return 0; 433 } 434 return -1; 435 } 436 EXPORT_SYMBOL(seq_putc); 437 438 int seq_puts(struct seq_file *m, const char *s) 439 { 440 int len = strlen(s); 441 if (m->count + len < m->size) { 442 memcpy(m->buf + m->count, s, len); 443 m->count += len; 444 return 0; 445 } 446 m->count = m->size; 447 return -1; 448 } 449 EXPORT_SYMBOL(seq_puts); 450