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 + 1); 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 int ret; 83 84 ret = sbuf_bcpy(seq->buf, data, len); 85 if (ret == 0) 86 seq->size = sbuf_len(seq->buf); 87 88 return (ret); 89 } 90 91 void 92 seq_putc(struct seq_file *seq, char c) 93 { 94 int ret; 95 96 ret = sbuf_putc(seq->buf, c); 97 if (ret == 0) 98 seq->size = sbuf_len(seq->buf); 99 } 100 101 void 102 seq_puts(struct seq_file *seq, const char *str) 103 { 104 int ret; 105 106 ret = sbuf_printf(seq->buf, "%s", str); 107 if (ret == 0) 108 seq->size = sbuf_len(seq->buf); 109 } 110 111 /* 112 * This only needs to be a valid address for lkpi 113 * drivers it should never actually be called 114 */ 115 off_t 116 seq_lseek(struct linux_file *file, off_t offset, int whence) 117 { 118 119 panic("%s not supported\n", __FUNCTION__); 120 return (0); 121 } 122 123 static void * 124 single_start(struct seq_file *p, off_t *pos) 125 { 126 127 return ((void *)(uintptr_t)(*pos == 0)); 128 } 129 130 static void * 131 single_next(struct seq_file *p, void *v, off_t *pos) 132 { 133 134 ++*pos; 135 return (NULL); 136 } 137 138 static void 139 single_stop(struct seq_file *p, void *v) 140 { 141 } 142 143 static int 144 _seq_open_without_sbuf(struct linux_file *f, const struct seq_operations *op) 145 { 146 struct seq_file *p; 147 148 if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL) 149 return (-ENOMEM); 150 151 p->file = f; 152 p->op = op; 153 f->private_data = (void *) p; 154 return (0); 155 } 156 157 int 158 seq_open(struct linux_file *f, const struct seq_operations *op) 159 { 160 int ret; 161 162 ret = _seq_open_without_sbuf(f, op); 163 if (ret == 0) 164 ((struct seq_file *)f->private_data)->buf = sbuf_new_auto(); 165 166 return (ret); 167 } 168 169 void * 170 __seq_open_private(struct linux_file *f, const struct seq_operations *op, int size) 171 { 172 struct seq_file *seq_file; 173 void *private; 174 int error; 175 176 private = malloc(size, M_LSEQ, M_NOWAIT|M_ZERO); 177 if (private == NULL) 178 return (NULL); 179 180 error = seq_open(f, op); 181 if (error < 0) { 182 free(private, M_LSEQ); 183 return (NULL); 184 } 185 186 seq_file = (struct seq_file *)f->private_data; 187 seq_file->private = private; 188 189 return (private); 190 } 191 192 static int 193 _single_open_without_sbuf(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d) 194 { 195 struct seq_operations *op; 196 int rc = -ENOMEM; 197 198 op = malloc(sizeof(*op), M_LSEQ, M_NOWAIT); 199 if (op) { 200 op->start = single_start; 201 op->next = single_next; 202 op->stop = single_stop; 203 op->show = show; 204 rc = _seq_open_without_sbuf(f, op); 205 if (rc) 206 free(op, M_LSEQ); 207 else 208 ((struct seq_file *)f->private_data)->private = d; 209 } 210 return (rc); 211 } 212 213 int 214 single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d) 215 { 216 int ret; 217 218 ret = _single_open_without_sbuf(f, show, d); 219 if (ret == 0) 220 ((struct seq_file *)f->private_data)->buf = sbuf_new_auto(); 221 222 return (ret); 223 } 224 225 int 226 single_open_size(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d, size_t size) 227 { 228 int ret; 229 230 ret = _single_open_without_sbuf(f, show, d); 231 if (ret == 0) 232 ((struct seq_file *)f->private_data)->buf = sbuf_new( 233 NULL, NULL, size, SBUF_AUTOEXTEND); 234 235 return (ret); 236 } 237 238 int 239 seq_release(struct inode *inode __unused, struct linux_file *file) 240 { 241 struct seq_file *m; 242 struct sbuf *s; 243 244 m = file->private_data; 245 s = m->buf; 246 247 sbuf_delete(s); 248 free(m, M_LSEQ); 249 250 return (0); 251 } 252 253 int 254 seq_release_private(struct inode *inode __unused, struct linux_file *f) 255 { 256 struct seq_file *seq; 257 258 seq = (struct seq_file *)f->private_data; 259 free(seq->private, M_LSEQ); 260 return (seq_release(inode, f)); 261 } 262 263 int 264 single_release(struct vnode *v, struct linux_file *f) 265 { 266 const struct seq_operations *op; 267 struct seq_file *m; 268 int rc; 269 270 /* be NULL safe */ 271 if ((m = f->private_data) == NULL) 272 return (0); 273 274 op = m->op; 275 rc = seq_release(v, f); 276 free(__DECONST(void *, op), M_LSEQ); 277 return (rc); 278 } 279 280 void 281 lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args) 282 { 283 int ret; 284 285 ret = sbuf_vprintf(m->buf, fmt, args); 286 if (ret == 0) 287 m->size = sbuf_len(m->buf); 288 } 289 290 void 291 lkpi_seq_printf(struct seq_file *m, const char *fmt, ...) 292 { 293 va_list args; 294 295 va_start(args, fmt); 296 lkpi_seq_vprintf(m, fmt, args); 297 va_end(args); 298 } 299 300 bool 301 seq_has_overflowed(struct seq_file *m) 302 { 303 return (sbuf_len(m->buf) == -1); 304 } 305