1b2441318SGreg Kroah-Hartman// SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds/*
31da177e4SLinus Torvalds * linux/fs/seq_file.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * helper functions for making synthetic files from sequences of records.
61da177e4SLinus Torvalds * initial implementation -- AV, Oct 2001.
71da177e4SLinus Torvalds */
81da177e4SLinus Torvalds
9a3963015SJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10a3963015SJoe Perches
1109652320SAlexey Dobriyan#include <linux/cache.h>
121da177e4SLinus Torvalds#include <linux/fs.h>
13630d9c47SPaul Gortmaker#include <linux/export.h>
141da177e4SLinus Torvalds#include <linux/seq_file.h>
15058504edSHeiko Carstens#include <linux/vmalloc.h>
161da177e4SLinus Torvalds#include <linux/slab.h>
17adb37c4cSEric W. Biederman#include <linux/cred.h>
18058504edSHeiko Carstens#include <linux/mm.h>
1937607102SAndy Shevchenko#include <linux/printk.h>
2025c6bb76SAndy Shevchenko#include <linux/string_helpers.h>
21d4d50710SChristoph Hellwig#include <linux/uio.h>
221da177e4SLinus Torvalds
237c0f6ba6SLinus Torvalds#include <linux/uaccess.h>
241da177e4SLinus Torvalds#include <asm/page.h>
251da177e4SLinus Torvalds
2609652320SAlexey Dobriyanstatic struct kmem_cache *seq_file_cache __ro_after_init;
2709652320SAlexey Dobriyan
28e075f591SKAMEZAWA Hiroyukistatic void seq_set_overflow(struct seq_file *m)
29e075f591SKAMEZAWA Hiroyuki{
30e075f591SKAMEZAWA Hiroyuki	m->count = m->size;
31e075f591SKAMEZAWA Hiroyuki}
32e075f591SKAMEZAWA Hiroyuki
33058504edSHeiko Carstensstatic void *seq_buf_alloc(unsigned long size)
34058504edSHeiko Carstens{
358cae8cd8SEric Sandeen	if (unlikely(size > MAX_RW_COUNT))
368cae8cd8SEric Sandeen		return NULL;
378cae8cd8SEric Sandeen
38d64d01a1SAlexey Dobriyan	return kvmalloc(size, GFP_KERNEL_ACCOUNT);
39058504edSHeiko Carstens}
40058504edSHeiko Carstens
411da177e4SLinus Torvalds/**
421da177e4SLinus Torvalds *	seq_open -	initialize sequential file
431da177e4SLinus Torvalds *	@file: file we initialize
441da177e4SLinus Torvalds *	@op: method table describing the sequence
451da177e4SLinus Torvalds *
461da177e4SLinus Torvalds *	seq_open() sets @file, associating it with a sequence described
471da177e4SLinus Torvalds *	by @op.  @op->start() sets the iterator up and returns the first
481da177e4SLinus Torvalds *	element of sequence. @op->stop() shuts it down.  @op->next()
491da177e4SLinus Torvalds *	returns the next element of sequence.  @op->show() prints element
501da177e4SLinus Torvalds *	into the buffer.  In case of error ->start() and ->next() return
511da177e4SLinus Torvalds *	ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
521da177e4SLinus Torvalds *	returns 0 in case of success and negative number in case of error.
53521b5d0cSAl Viro *	Returning SEQ_SKIP means "discard this element and move on".
54460b865eSYann Droneaud *	Note: seq_open() will allocate a struct seq_file and store its
55460b865eSYann Droneaud *	pointer in @file->private_data. This pointer should not be modified.
561da177e4SLinus Torvalds */
5715ad7cdcSHelge Dellerint seq_open(struct file *file, const struct seq_operations *op)
581da177e4SLinus Torvalds{
59189f9841SYann Droneaud	struct seq_file *p;
60189f9841SYann Droneaud
61189f9841SYann Droneaud	WARN_ON(file->private_data);
62189f9841SYann Droneaud
6309652320SAlexey Dobriyan	p = kmem_cache_zalloc(seq_file_cache, GFP_KERNEL);
64189f9841SYann Droneaud	if (!p)
65189f9841SYann Droneaud		return -ENOMEM;
66189f9841SYann Droneaud
67189f9841SYann Droneaud	file->private_data = p;
681abe77b0SAl Viro
690ac1759aSIngo Molnar	mutex_init(&p->lock);
701da177e4SLinus Torvalds	p->op = op;
7134dbbcdbSLinus Torvalds
7234dbbcdbSLinus Torvalds	// No refcounting: the lifetime of 'p' is constrained
7334dbbcdbSLinus Torvalds	// to the lifetime of the file.
7434dbbcdbSLinus Torvalds	p->file = file;
751da177e4SLinus Torvalds
768f19d472SEric Biederman	/*
778f19d472SEric Biederman	 * seq_files support lseek() and pread().  They do not implement
788f19d472SEric Biederman	 * write() at all, but we clear FMODE_PWRITE here for historical
798f19d472SEric Biederman	 * reasons.
808f19d472SEric Biederman	 *
818f19d472SEric Biederman	 * If a client of seq_files a) implements file.write() and b) wishes to
828f19d472SEric Biederman	 * support pwrite() then that client will need to implement its own
838f19d472SEric Biederman	 * file.open() which calls seq_open() and then sets FMODE_PWRITE.
848f19d472SEric Biederman	 */
858f19d472SEric Biederman	file->f_mode &= ~FMODE_PWRITE;
861da177e4SLinus Torvalds	return 0;
871da177e4SLinus Torvalds}
881da177e4SLinus TorvaldsEXPORT_SYMBOL(seq_open);
891da177e4SLinus Torvalds
9033da8892SEric Biedermanstatic int traverse(struct seq_file *m, loff_t offset)
9133da8892SEric Biederman{
921f4aace6SNeilBrown	loff_t pos = 0;
9333da8892SEric Biederman	int error = 0;
9433da8892SEric Biederman	void *p;
9533da8892SEric Biederman
961f4aace6SNeilBrown	m->index = 0;
9733da8892SEric Biederman	m->count = m->from = 0;
981f4aace6SNeilBrown	if (!offset)
9933da8892SEric Biederman		return 0;
10133da8892SEric Biederman	if (!m->buf) {
102058504edSHeiko Carstens		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
10333da8892SEric Biederman		if (!m->buf)
10433da8892SEric Biederman			return -ENOMEM;
10533da8892SEric Biederman	}
1061f4aace6SNeilBrown	p = m->op->start(m, &m->index);
10733da8892SEric Biederman	while (p) {
10833da8892SEric Biederman		error = PTR_ERR(p);
10933da8892SEric Biederman		if (IS_ERR(p))
11033da8892SEric Biederman			break;
11133da8892SEric Biederman		error = m->op->show(m, p);
11233da8892SEric Biederman		if (error < 0)
11333da8892SEric Biederman			break;
11433da8892SEric Biederman		if (unlikely(error)) {
11533da8892SEric Biederman			error = 0;
11633da8892SEric Biederman			m->count = 0;
11733da8892SEric Biederman		}
1181f33c41cSJoe Perches		if (seq_has_overflowed(m))
11933da8892SEric Biederman			goto Eoverflow;
1206a2aeab5SNeilBrown		p = m->op->next(m, p, &m->index);
12133da8892SEric Biederman		if (pos + m->count > offset) {
12233da8892SEric Biederman			m->from = offset - pos;
12333da8892SEric Biederman			m->count -= m->from;
12433da8892SEric Biederman			break;
12533da8892SEric Biederman		}
12633da8892SEric Biederman		pos += m->count;
12733da8892SEric Biederman		m->count = 0;
1281f4aace6SNeilBrown		if (pos == offset)
12933da8892SEric Biederman			break;
13033da8892SEric Biederman	}
13133da8892SEric Biederman	m->op->stop(m, p);
13233da8892SEric Biederman	return error;
13333da8892SEric Biederman
13433da8892SEric BiedermanEoverflow:
13533da8892SEric Biederman	m->op->stop(m, p);
136058504edSHeiko Carstens	kvfree(m->buf);
137801a7605SAl Viro	m->count = 0;
138058504edSHeiko Carstens	m->buf = seq_buf_alloc(m->size <<= 1);
13933da8892SEric Biederman	return !m->buf ? -ENOMEM : -EAGAIN;
14033da8892SEric Biederman}
14133da8892SEric Biederman
1421da177e4SLinus Torvalds/**
1431da177e4SLinus Torvalds *	seq_read -	->read() method for sequential files.
14467be2dd1SMartin Waitz *	@file: the file to read from
14567be2dd1SMartin Waitz *	@buf: the buffer to read to
14667be2dd1SMartin Waitz *	@size: the maximum number of bytes to read
14767be2dd1SMartin Waitz *	@ppos: the current position in the file
1481da177e4SLinus Torvalds *
1491da177e4SLinus Torvalds *	Ready-made ->f_op->read()
1501da177e4SLinus Torvalds */
1511da177e4SLinus Torvaldsssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
1521da177e4SLinus Torvalds{
153d4d50710SChristoph Hellwig	struct iovec iov = { .iov_base = buf, .iov_len = size};
154d4d50710SChristoph Hellwig	struct kiocb kiocb;
155d4d50710SChristoph Hellwig	struct iov_iter iter;
156d4d50710SChristoph Hellwig	ssize_t ret;
157d4d50710SChristoph Hellwig
158d4d50710SChristoph Hellwig	init_sync_kiocb(&kiocb, file);
159d4d50710SChristoph Hellwig	iov_iter_init(&iter, READ, &iov, 1, size);
160d4d50710SChristoph Hellwig
161d4d50710SChristoph Hellwig	kiocb.ki_pos = *ppos;
162d4d50710SChristoph Hellwig	ret = seq_read_iter(&kiocb, &iter);
163d4d50710SChristoph Hellwig	*ppos = kiocb.ki_pos;
164d4d50710SChristoph Hellwig	return ret;
165d4d50710SChristoph Hellwig}
166d4d50710SChristoph HellwigEXPORT_SYMBOL(seq_read);
167d4d50710SChristoph Hellwig
168d4d50710SChristoph Hellwig/*
169d4d50710SChristoph Hellwig * Ready-made ->f_op->read_iter()
170d4d50710SChristoph Hellwig */
171d4d50710SChristoph Hellwigssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)
172d4d50710SChristoph Hellwig{
173d4d50710SChristoph Hellwig	struct seq_file *m = iocb->ki_filp->private_data;
1741da177e4SLinus Torvalds	size_t copied = 0;
1751da177e4SLinus Torvalds	size_t n;
1761da177e4SLinus Torvalds	void *p;
1771da177e4SLinus Torvalds	int err = 0;
1781da177e4SLinus Torvalds
1794bbf439bSAl Viro	if (!iov_iter_count(iter))
1804bbf439bSAl Viro		return 0;
1814bbf439bSAl Viro
1820ac1759aSIngo Molnar	mutex_lock(&m->lock);
1838f19d472SEric Biederman
184e522751dSTomasz Majchrzak	/*
185e522751dSTomasz Majchrzak	 * if request is to read from zero offset, reset iterator to first
186e522751dSTomasz Majchrzak	 * record as it might have been already advanced by previous requests
187e522751dSTomasz Majchrzak	 */
188d4d50710SChristoph Hellwig	if (iocb->ki_pos == 0) {
189e522751dSTomasz Majchrzak		m->index = 0;
190cf5eebaeSMiklos Szeredi		m->count = 0;
191cf5eebaeSMiklos Szeredi	}
192e522751dSTomasz Majchrzak
193d4d50710SChristoph Hellwig	/* Don't assume ki_pos is where we left it */
194d4d50710SChristoph Hellwig	if (unlikely(iocb->ki_pos != m->read_pos)) {
195d4d50710SChristoph Hellwig		while ((err = traverse(m, iocb->ki_pos)) == -EAGAIN)
1968f19d472SEric Biederman			;
1978f19d472SEric Biederman		if (err) {
1988f19d472SEric Biederman			/* With prejudice... */
1998f19d472SEric Biederman			m->read_pos = 0;
2008f19d472SEric Biederman			m->index = 0;
2018f19d472SEric Biederman			m->count = 0;
2028f19d472SEric Biederman			goto Done;
2037904ac84SEarl Chew		} else {
204d4d50710SChristoph Hellwig			m->read_pos = iocb->ki_pos;
2058f19d472SEric Biederman		}
2068f19d472SEric Biederman	}
2078f19d472SEric Biederman
2081da177e4SLinus Torvalds	/* grab buffer if we didn't have one */
2091da177e4SLinus Torvalds	if (!m->buf) {
210058504edSHeiko Carstens		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
2111da177e4SLinus Torvalds		if (!m->buf)
2121da177e4SLinus Torvalds			goto Enomem;
2131da177e4SLinus Torvalds	}
2144bbf439bSAl Viro	// something left in the buffer - copy it out first
2151da177e4SLinus Torvalds	if (m->count) {
2164bbf439bSAl Viro		n = copy_to_iter(m->buf + m->from, m->count, iter);
2171da177e4SLinus Torvalds		m->count -= n;
2181da177e4SLinus Torvalds		m->from += n;
2191da177e4SLinus Torvalds		copied += n;
2204bbf439bSAl Viro		if (m->count)	// hadn't managed to copy everything
2211da177e4SLinus Torvalds			goto Done;
2221da177e4SLinus Torvalds	}
2234bbf439bSAl Viro	// get a non-empty record in the buffer
2241f4aace6SNeilBrown	m->from = 0;
2251f4aace6SNeilBrown	p = m->op->start(m, &m->index);
2261da177e4SLinus Torvalds	while (1) {
2271da177e4SLinus Torvalds		err = PTR_ERR(p);
2284bbf439bSAl Viro		if (!p || IS_ERR(p))	// EOF or an error
2291da177e4SLinus Torvalds			break;
2301da177e4SLinus Torvalds		err = m->op->show(m, p);
2314bbf439bSAl Viro		if (err < 0)		// hard error
2321da177e4SLinus Torvalds			break;
2334bbf439bSAl Viro		if (unlikely(err))	// ->show() says "skip it"
234521b5d0cSAl Viro			m->count = 0;
2354bbf439bSAl Viro		if (unlikely(!m->count)) { // empty record
2361f4aace6SNeilBrown			p = m->op->next(m, p, &m->index);
2374cdfe84bSAl Viro			continue;
2384cdfe84bSAl Viro		}
2394bbf439bSAl Viro		if (!seq_has_overflowed(m)) // got it
2401da177e4SLinus Torvalds			goto Fill;
2414bbf439bSAl Viro		// need a bigger buffer
2421da177e4SLinus Torvalds		m->op->stop(m, p);
243058504edSHeiko Carstens		kvfree(m->buf);
244801a7605SAl Viro		m->count = 0;
245058504edSHeiko Carstens		m->buf = seq_buf_alloc(m->size <<= 1);
2461da177e4SLinus Torvalds		if (!m->buf)
2471da177e4SLinus Torvalds			goto Enomem;
2481f4aace6SNeilBrown		p = m->op->start(m, &m->index);
2491da177e4SLinus Torvalds	}
2504bbf439bSAl Viro	// EOF or an error
2511da177e4SLinus Torvalds	m->op->stop(m, p);
2521da177e4SLinus Torvalds	m->count = 0;
2531da177e4SLinus Torvalds	goto Done;
2541da177e4SLinus TorvaldsFill:
2554bbf439bSAl Viro	// one non-empty record is in the buffer; if they want more,
2564bbf439bSAl Viro	// try to fit more in, but in any case we need to advance
2574bbf439bSAl Viro	// the iterator once for every record shown.
2581f4aace6SNeilBrown	while (1) {
2591da177e4SLinus Torvalds		size_t offs = m->count;
2601f4aace6SNeilBrown		loff_t pos = m->index;
2621f4aace6SNeilBrown		p = m->op->next(m, p, &m->index);
2633bfa7e14SVasily Averin		if (pos == m->index) {
264a3963015SJoe Perches			pr_info_ratelimited("buggy .next function %ps did not update position index\n",
265a3963015SJoe Perches					    m->op->next);
2661f4aace6SNeilBrown			m->index++;
2673bfa7e14SVasily Averin		}
2684bbf439bSAl Viro		if (!p || IS_ERR(p))	// no next record for us
2691da177e4SLinus Torvalds			break;
2704bbf439bSAl Viro		if (m->count >= iov_iter_count(iter))
2711f4aace6SNeilBrown			break;
2721da177e4SLinus Torvalds		err = m->op->show(m, p);
2734bbf439bSAl Viro		if (err > 0) {		// ->show() says "skip it"
2741da177e4SLinus Torvalds			m->count = offs;
2754bbf439bSAl Viro		} else if (err || seq_has_overflowed(m)) {
2764bbf439bSAl Viro			m->count = offs;
2774bbf439bSAl Viro			break;
2781da177e4SLinus Torvalds		}
2791da177e4SLinus Torvalds	}
2801da177e4SLinus Torvalds	m->op->stop(m, p);
2814bbf439bSAl Viro	n = copy_to_iter(m->buf, m->count, iter);
2821da177e4SLinus Torvalds	copied += n;
2831da177e4SLinus Torvalds	m->count -= n;
2841f4aace6SNeilBrown	m->from = n;
2851da177e4SLinus TorvaldsDone:
2864bbf439bSAl Viro	if (unlikely(!copied)) {
2874bbf439bSAl Viro		copied = m->count ? -EFAULT : err;
2884bbf439bSAl Viro	} else {
289d4d50710SChristoph Hellwig		iocb->ki_pos += copied;
2908f19d472SEric Biederman		m->read_pos += copied;
2918f19d472SEric Biederman	}
2920ac1759aSIngo Molnar	mutex_unlock(&m->lock);
2931da177e4SLinus Torvalds	return copied;
2941da177e4SLinus TorvaldsEnomem:
2951da177e4SLinus Torvalds	err = -ENOMEM;
2961da177e4SLinus Torvalds	goto Done;
2971da177e4SLinus Torvalds}
298d4d50710SChristoph HellwigEXPORT_SYMBOL(seq_read_iter);
2991da177e4SLinus Torvalds
3001da177e4SLinus Torvalds/**
3011da177e4SLinus Torvalds *	seq_lseek -	->llseek() method for sequential files.
30267be2dd1SMartin Waitz *	@file: the file in question
30367be2dd1SMartin Waitz *	@offset: new position
304254adaa4SRandy Dunlap *	@whence: 0 for absolute, 1 for relative position
3051da177e4SLinus Torvalds *
3061da177e4SLinus Torvalds *	Ready-made ->f_op->llseek()
3071da177e4SLinus Torvalds */
308965c8e59SAndrew Mortonloff_t seq_lseek(struct file *file, loff_t offset, int whence)
3091da177e4SLinus Torvalds{
3108209e2f4SJoe Perches	struct seq_file *m = file->private_data;
31116abef0eSDavid Sterba	loff_t retval = -EINVAL;
3121da177e4SLinus Torvalds
3130ac1759aSIngo Molnar	mutex_lock(&m->lock);
314965c8e59SAndrew Morton	switch (whence) {
3155e62adefSAndrew Morton	case SEEK_CUR:
3165e62adefSAndrew Morton		offset += file->f_pos;
317df561f66SGustavo A. R. Silva		fallthrough;
3185e62adefSAndrew Morton	case SEEK_SET:
3195e62adefSAndrew Morton		if (offset < 0)
3205e62adefSAndrew Morton			break;
3215e62adefSAndrew Morton		retval = offset;
3225e62adefSAndrew Morton		if (offset != m->read_pos) {
3235e62adefSAndrew Morton			while ((retval = traverse(m, offset)) == -EAGAIN)
3245e62adefSAndrew Morton				;
3255e62adefSAndrew Morton			if (retval) {
3265e62adefSAndrew Morton				/* with extreme prejudice... */
3275e62adefSAndrew Morton				file->f_pos = 0;
3285e62adefSAndrew Morton				m->read_pos = 0;
3295e62adefSAndrew Morton				m->index = 0;
3305e62adefSAndrew Morton				m->count = 0;
3315e62adefSAndrew Morton			} else {
3325e62adefSAndrew Morton				m->read_pos = offset;
3335e62adefSAndrew Morton				retval = file->f_pos = offset;
3341da177e4SLinus Torvalds			}
33505e16745SGu Zheng		} else {
33605e16745SGu Zheng			file->f_pos = offset;
3375e62adefSAndrew Morton		}
3381da177e4SLinus Torvalds	}
33900c5746dSAlexey Dobriyan	mutex_unlock(&m->lock);
3401da177e4SLinus Torvalds	return retval;
3411da177e4SLinus Torvalds}
3421da177e4SLinus TorvaldsEXPORT_SYMBOL(seq_lseek);
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds/**
3451da177e4SLinus Torvalds *	seq_release -	free the structures associated with sequential file.
3461da177e4SLinus Torvalds *	@file: file in question
3476131ffaaSAl Viro *	@inode: its inode
3481da177e4SLinus Torvalds *
3491da177e4SLinus Torvalds *	Frees the structures associated with sequential file; can be used
3501da177e4SLinus Torvalds *	as ->f_op->release() if you don't have private data to destroy.
3511da177e4SLinus Torvalds */
3521da177e4SLinus Torvaldsint seq_release(struct inode *inode, struct file *file)
3531da177e4SLinus Torvalds{
3548209e2f4SJoe Perches	struct seq_file *m = file->private_data;
355058504edSHeiko Carstens	kvfree(m->buf);
35609652320SAlexey Dobriyan	kmem_cache_free(seq_file_cache, m);
3571da177e4SLinus Torvalds	return 0;
3581da177e4SLinus Torvalds}
3591da177e4SLinus TorvaldsEXPORT_SYMBOL(seq_release);
3601da177e4SLinus Torvalds
3611d31aa17SAndy Shevchenko/**
3621d31aa17SAndy Shevchenko * seq_escape_mem - print data into buffer, escaping some characters
3631d31aa17SAndy Shevchenko * @m: target buffer
3641d31aa17SAndy Shevchenko * @src: source buffer
3651d31aa17SAndy Shevchenko * @len: size of source buffer
3661d31aa17SAndy Shevchenko * @flags: flags to pass to string_escape_mem()
3671d31aa17SAndy Shevchenko * @esc: set of characters that need escaping
3681d31aa17SAndy Shevchenko *
3691d31aa17SAndy Shevchenko * Puts data into buffer, replacing each occurrence of character from
3701d31aa17SAndy Shevchenko * given class (defined by @flags and @esc) with printable escaped sequence.
3711d31aa17SAndy Shevchenko *
3721d31aa17SAndy Shevchenko * Use seq_has_overflowed() to check for errors.
3731d31aa17SAndy Shevchenko */
3741d31aa17SAndy Shevchenkovoid seq_escape_mem(struct seq_file *m, const char *src, size_t len,
3751d31aa17SAndy Shevchenko		    unsigned int flags, const char *esc)
3761d31aa17SAndy Shevchenko{
3771d31aa17SAndy Shevchenko	char *buf;
3781d31aa17SAndy Shevchenko	size_t size = seq_get_buf(m, &buf);
3791d31aa17SAndy Shevchenko	int ret;
3801d31aa17SAndy Shevchenko
3811d31aa17SAndy Shevchenko	ret = string_escape_mem(src, len, buf, size, flags, esc);
3821d31aa17SAndy Shevchenko	seq_commit(m, ret < size ? ret : -1);
3831d31aa17SAndy Shevchenko}
3841d31aa17SAndy ShevchenkoEXPORT_SYMBOL(seq_escape_mem);
3851d31aa17SAndy Shevchenko
3866798a8caSJoe Perchesvoid seq_vprintf(struct seq_file *m, const char *f, va_list args)
3871da177e4SLinus Torvalds{
3881da177e4SLinus Torvalds	int len;
3891da177e4SLinus Torvalds
3901da177e4SLinus Torvalds	if (m->count < m->size) {
3911da177e4SLinus Torvalds		len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
3921da177e4SLinus Torvalds		if (m->count + len < m->size) {
3931da177e4SLinus Torvalds			m->count += len;
3946798a8caSJoe Perches			return;
3951da177e4SLinus Torvalds		}
3961da177e4SLinus Torvalds	}
397e075f591SKAMEZAWA Hiroyuki	seq_set_overflow(m);
3981da177e4SLinus Torvalds}
399a4808147SSteven WhitehouseEXPORT_SYMBOL(seq_vprintf);
400a4808147SSteven Whitehouse
4016798a8caSJoe Perchesvoid seq_printf(struct seq_file *m, const char *f, ...)
402a4808147SSteven Whitehouse{
403a4808147SSteven Whitehouse	va_list args;
404a4808147SSteven Whitehouse
405a4808147SSteven Whitehouse	va_start(args, f);
4066798a8caSJoe Perches	seq_vprintf(m, f, args);
407a4808147SSteven Whitehouse	va_end(args);
408a4808147SSteven Whitehouse}
4091da177e4SLinus TorvaldsEXPORT_SYMBOL(seq_printf);
4101da177e4SLinus Torvalds
41176d6a133SFlorent Revest#ifdef CONFIG_BINARY_PRINTF
41276d6a133SFlorent Revestvoid seq_bprintf(struct seq_file *m, const char *f, const u32 *binary)
41376d6a133SFlorent Revest{
41476d6a133SFlorent Revest	int len;
41576d6a133SFlorent Revest
41676d6a133SFlorent Revest	if (m->count < m->size) {
41776d6a133SFlorent Revest		len = bstr_printf(m->buf + m->count, m->size - m->count, f,
41876d6a133SFlorent Revest				  binary);
41976d6a133SFlorent Revest		if (m->count + len < m->size) {
42076d6a133SFlorent Revest			m->count += len;
42176d6a133SFlorent Revest			return;
42276d6a133SFlorent Revest		}
42376d6a133SFlorent Revest	}
42476d6a133SFlorent Revest	seq_set_overflow(m);
42576d6a133SFlorent Revest}
42676d6a133SFlorent RevestEXPORT_SYMBOL(seq_bprintf);
42776d6a133SFlorent Revest#endif /* CONFIG_BINARY_PRINTF */
42876d6a133SFlorent Revest
42974e2f334STörök Edwin/**
430958086d1STörök Edwin *	mangle_path -	mangle and copy path to buffer beginning
431958086d1STörök Edwin *	@s: buffer start
432958086d1STörök Edwin *	@p: beginning of path in above buffer
433958086d1STörök Edwin *	@esc: set of characters that need escaping
43474e2f334STörök Edwin *
43574e2f334STörök Edwin *      Copy the path from @p to @s, replacing each occurrence of character from