Path: blob/main/sys/compat/linuxkpi/common/src/linux_seq_file.c
39586 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2016-2018, Matthew Macy <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*26*/2728#include <sys/types.h>29#include <sys/systm.h>30#include <sys/param.h>31#include <sys/sbuf.h>32#include <sys/syslog.h>33#include <sys/vnode.h>3435#include <linux/seq_file.h>36#include <linux/file.h>3738#undef file39MALLOC_DEFINE(M_LSEQ, "seq_file", "seq_file");4041ssize_t42seq_read(struct linux_file *f, char *ubuf, size_t size, off_t *ppos)43{44struct seq_file *m;45struct sbuf *sbuf;46void *p;47ssize_t rc;4849m = f->private_data;50sbuf = m->buf;5152p = m->op->start(m, ppos);53rc = m->op->show(m, p);54if (rc)55return (rc);5657rc = sbuf_finish(sbuf);58if (rc)59return (rc);6061rc = sbuf_len(sbuf);62if (*ppos >= rc || size < 1)63return (-EINVAL);6465size = min(rc - *ppos, size);66memcpy(ubuf, sbuf_data(sbuf) + *ppos, size);67*ppos += size;6869return (size);70}7172int73seq_write(struct seq_file *seq, const void *data, size_t len)74{75int ret;7677ret = sbuf_bcpy(seq->buf, data, len);78if (ret == 0)79seq->size = sbuf_len(seq->buf);8081return (ret);82}8384void85seq_putc(struct seq_file *seq, char c)86{87int ret;8889ret = sbuf_putc(seq->buf, c);90if (ret == 0)91seq->size = sbuf_len(seq->buf);92}9394void95seq_puts(struct seq_file *seq, const char *str)96{97int ret;9899ret = sbuf_printf(seq->buf, "%s", str);100if (ret == 0)101seq->size = sbuf_len(seq->buf);102}103104/*105* This only needs to be a valid address for lkpi106* drivers it should never actually be called107*/108off_t109seq_lseek(struct linux_file *file, off_t offset, int whence)110{111112panic("%s not supported\n", __FUNCTION__);113return (0);114}115116static void *117single_start(struct seq_file *p, off_t *pos)118{119120return ((void *)(uintptr_t)(*pos == 0));121}122123static void *124single_next(struct seq_file *p, void *v, off_t *pos)125{126127++*pos;128return (NULL);129}130131static void132single_stop(struct seq_file *p, void *v)133{134}135136static int137_seq_open_without_sbuf(struct linux_file *f, const struct seq_operations *op)138{139struct seq_file *p;140141if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL)142return (-ENOMEM);143144p->file = f;145p->op = op;146f->private_data = (void *) p;147return (0);148}149150int151seq_open(struct linux_file *f, const struct seq_operations *op)152{153int ret;154155ret = _seq_open_without_sbuf(f, op);156if (ret == 0)157((struct seq_file *)f->private_data)->buf = sbuf_new_auto();158159return (ret);160}161162void *163__seq_open_private(struct linux_file *f, const struct seq_operations *op, int size)164{165struct seq_file *seq_file;166void *private;167int error;168169private = malloc(size, M_LSEQ, M_NOWAIT|M_ZERO);170if (private == NULL)171return (NULL);172173error = seq_open(f, op);174if (error < 0) {175free(private, M_LSEQ);176return (NULL);177}178179seq_file = (struct seq_file *)f->private_data;180seq_file->private = private;181182return (private);183}184185static int186_single_open_without_sbuf(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)187{188struct seq_operations *op;189int rc = -ENOMEM;190191op = malloc(sizeof(*op), M_LSEQ, M_NOWAIT);192if (op) {193op->start = single_start;194op->next = single_next;195op->stop = single_stop;196op->show = show;197rc = _seq_open_without_sbuf(f, op);198if (rc)199free(op, M_LSEQ);200else201((struct seq_file *)f->private_data)->private = d;202}203return (rc);204}205206int207single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)208{209int ret;210211ret = _single_open_without_sbuf(f, show, d);212if (ret == 0)213((struct seq_file *)f->private_data)->buf = sbuf_new_auto();214215return (ret);216}217218int219single_open_size(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d, size_t size)220{221int ret;222223ret = _single_open_without_sbuf(f, show, d);224if (ret == 0)225((struct seq_file *)f->private_data)->buf = sbuf_new(226NULL, NULL, size, SBUF_AUTOEXTEND);227228return (ret);229}230231int232seq_release(struct inode *inode __unused, struct linux_file *file)233{234struct seq_file *m;235struct sbuf *s;236237m = file->private_data;238s = m->buf;239240sbuf_delete(s);241free(m, M_LSEQ);242243return (0);244}245246int247seq_release_private(struct inode *inode __unused, struct linux_file *f)248{249struct seq_file *seq;250251seq = (struct seq_file *)f->private_data;252free(seq->private, M_LSEQ);253return (seq_release(inode, f));254}255256int257single_release(struct vnode *v, struct linux_file *f)258{259const struct seq_operations *op;260struct seq_file *m;261int rc;262263/* be NULL safe */264if ((m = f->private_data) == NULL)265return (0);266267op = m->op;268rc = seq_release(v, f);269free(__DECONST(void *, op), M_LSEQ);270return (rc);271}272273void274lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args)275{276int ret;277278ret = sbuf_vprintf(m->buf, fmt, args);279if (ret == 0)280m->size = sbuf_len(m->buf);281}282283void284lkpi_seq_printf(struct seq_file *m, const char *fmt, ...)285{286va_list args;287288va_start(args, fmt);289lkpi_seq_vprintf(m, fmt, args);290va_end(args);291}292293bool294seq_has_overflowed(struct seq_file *m)295{296return (sbuf_len(m->buf) == -1);297}298299300