1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/systm.h> 34 #include <sys/param.h> 35 #include <sys/sbuf.h> 36 #include <sys/syslog.h> 37 #include <sys/vnode.h> 38 39 #include <linux/seq_file.h> 40 #include <linux/file.h> 41 42 #undef file 43 MALLOC_DEFINE(M_LSEQ, "seq_file", "seq_file"); 44 45 ssize_t 46 seq_read(struct linux_file *f, char *ubuf, size_t size, off_t *ppos) 47 { 48 struct seq_file *m; 49 struct sbuf *sbuf; 50 void *p; 51 ssize_t rc; 52 53 m = f->private_data; 54 sbuf = m->buf; 55 56 p = m->op->start(m, ppos); 57 rc = m->op->show(m, p); 58 if (rc) 59 return (rc); 60 61 rc = sbuf_finish(sbuf); 62 if (rc) 63 return (rc); 64 65 rc = sbuf_len(sbuf); 66 if (*ppos >= rc || size < 1) 67 return (-EINVAL); 68 69 size = min(rc - *ppos, size); 70 rc = strscpy(ubuf, sbuf_data(sbuf) + *ppos, size); 71 72 /* add 1 for null terminator */ 73 if (rc > 0) 74 rc += 1; 75 76 return (rc); 77 } 78 79 int 80 seq_write(struct seq_file *seq, const void *data, size_t len) 81 { 82 83 return (sbuf_bcpy(seq->buf, data, len)); 84 } 85 86 /* 87 * This only needs to be a valid address for lkpi 88 * drivers it should never actually be called 89 */ 90 off_t 91 seq_lseek(struct linux_file *file, off_t offset, int whence) 92 { 93 94 panic("%s not supported\n", __FUNCTION__); 95 return (0); 96 } 97 98 static void * 99 single_start(struct seq_file *p, off_t *pos) 100 { 101 102 return ((void *)(uintptr_t)(*pos == 0)); 103 } 104 105 static void * 106 single_next(struct seq_file *p, void *v, off_t *pos) 107 { 108 109 ++*pos; 110 return (NULL); 111 } 112 113 static void 114 single_stop(struct seq_file *p, void *v) 115 { 116 } 117 118 int 119 seq_open(struct linux_file *f, const struct seq_operations *op) 120 { 121 struct seq_file *p; 122 123 if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL) 124 return (-ENOMEM); 125 126 p->buf = sbuf_new_auto(); 127 p->file = f; 128 p->op = op; 129 f->private_data = (void *) p; 130 return (0); 131 } 132 133 int 134 single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d) 135 { 136 struct seq_operations *op; 137 int rc = -ENOMEM; 138 139 op = malloc(sizeof(*op), M_LSEQ, M_NOWAIT); 140 if (op) { 141 op->start = single_start; 142 op->next = single_next; 143 op->stop = single_stop; 144 op->show = show; 145 rc = seq_open(f, op); 146 if (rc) 147 free(op, M_LSEQ); 148 else 149 ((struct seq_file *)f->private_data)->private = d; 150 } 151 return (rc); 152 } 153 154 int 155 seq_release(struct inode *inode __unused, struct linux_file *file) 156 { 157 struct seq_file *m; 158 struct sbuf *s; 159 160 m = file->private_data; 161 s = m->buf; 162 163 sbuf_delete(s); 164 free(m, M_LSEQ); 165 166 return (0); 167 } 168 169 int 170 single_release(struct vnode *v, struct linux_file *f) 171 { 172 const struct seq_operations *op; 173 struct seq_file *m; 174 int rc; 175 176 /* be NULL safe */ 177 if ((m = f->private_data) == NULL) 178 return (0); 179 180 op = m->op; 181 rc = seq_release(v, f); 182 free(__DECONST(void *, op), M_LSEQ); 183 return (rc); 184 } 185 186 void 187 lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args) 188 { 189 sbuf_vprintf(m->buf, fmt, args); 190 } 191 192 void 193 lkpi_seq_printf(struct seq_file *m, const char *fmt, ...) 194 { 195 va_list args; 196 197 va_start(args, fmt); 198 seq_vprintf(m, fmt, args); 199 va_end(args); 200 } 201