1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/types.h> 30 #include <sys/systm.h> 31 #include <sys/param.h> 32 #include <sys/sbuf.h> 33 #include <sys/syslog.h> 34 #include <sys/vnode.h> 35 36 #include <linux/seq_file.h> 37 #include <linux/file.h> 38 39 #undef file 40 MALLOC_DEFINE(M_LSEQ, "seq_file", "seq_file"); 41 42 ssize_t 43 seq_read(struct linux_file *f, char __user *ubuf, size_t size, off_t *ppos) 44 { 45 struct seq_file *m; 46 struct sbuf *sbuf; 47 void *p; 48 ssize_t rc, oldlen; 49 size_t todo; 50 51 m = f->private_data; 52 sbuf = m->buf; 53 sbuf_clear(sbuf); 54 55 p = m->op->start(m, ppos); 56 if (p == NULL) 57 return (0); 58 59 rc = 0; 60 while (size > sbuf_len(sbuf)) { 61 oldlen = sbuf_len(sbuf); 62 rc = m->op->show(m, p); 63 if (rc < 0) 64 break; 65 66 if (rc == SEQ_SKIP) { 67 /* Discard any data written in show callback. */ 68 sbuf_setpos(sbuf, oldlen); 69 rc = 0; 70 } 71 72 /* 73 * If the sbuf has overflowed, bail. Discard any 74 * partial output from the show callback for this item 75 * preserving output from any earlier items. Since we 76 * break before calling the next callback to update 77 * *ppos, a subsequent read() will start by displaying 78 * the current item. However, if the current item 79 * could not be displayed by itself, still fail with 80 * ENOMEM rather than returning EOF. 81 */ 82 if (sbuf_error(sbuf)) { 83 if (oldlen != 0) 84 sbuf_setpos(sbuf, oldlen); 85 break; 86 } 87 88 /* 89 * XXX: The seq_file documentation claims that Linux 90 * warns if this callback doesn't update the value in 91 * *ppos. We don't bother warning here. 92 */ 93 p = m->op->next(m, p, ppos); 94 if (p == NULL) 95 break; 96 } 97 m->op->stop(m, p); 98 99 if (rc < 0) 100 return (rc); 101 102 rc = sbuf_finish(sbuf); 103 if (rc != 0) 104 return (-rc); 105 106 todo = sbuf_len(sbuf); 107 if (todo > size) 108 todo = size; 109 110 rc = copy_to_user(ubuf, sbuf_data(sbuf), todo); 111 if (rc != 0) 112 return (-EFAULT); 113 114 return (todo); 115 } 116 117 int 118 seq_write(struct seq_file *seq, const void *data, size_t len) 119 { 120 int ret; 121 122 ret = sbuf_bcpy(seq->buf, data, len); 123 if (ret == 0) 124 seq->size = sbuf_len(seq->buf); 125 126 return (ret); 127 } 128 129 void 130 seq_putc(struct seq_file *seq, char c) 131 { 132 int ret; 133 134 ret = sbuf_putc(seq->buf, c); 135 if (ret == 0) 136 seq->size = sbuf_len(seq->buf); 137 } 138 139 void 140 seq_puts(struct seq_file *seq, const char *str) 141 { 142 int ret; 143 144 ret = sbuf_printf(seq->buf, "%s", str); 145 if (ret == 0) 146 seq->size = sbuf_len(seq->buf); 147 } 148 149 /* 150 * This only needs to be a valid address for lkpi 151 * drivers it should never actually be called 152 */ 153 off_t 154 seq_lseek(struct linux_file *file, off_t offset, int whence) 155 { 156 157 panic("%s not supported\n", __FUNCTION__); 158 return (0); 159 } 160 161 static void * 162 single_start(struct seq_file *p, off_t *pos) 163 { 164 165 return ((void *)(uintptr_t)(*pos == 0)); 166 } 167 168 static void * 169 single_next(struct seq_file *p, void *v, off_t *pos) 170 { 171 172 ++*pos; 173 return (NULL); 174 } 175 176 static void 177 single_stop(struct seq_file *p, void *v) 178 { 179 } 180 181 static int 182 _seq_open_without_sbuf(struct linux_file *f, const struct seq_operations *op) 183 { 184 struct seq_file *p; 185 186 if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL) 187 return (-ENOMEM); 188 189 p->file = f; 190 p->op = op; 191 f->private_data = (void *) p; 192 return (0); 193 } 194 195 int 196 seq_open(struct linux_file *f, const struct seq_operations *op) 197 { 198 int ret; 199 200 ret = _seq_open_without_sbuf(f, op); 201 if (ret == 0) 202 ((struct seq_file *)f->private_data)->buf = sbuf_new_auto(); 203 204 return (ret); 205 } 206 207 void * 208 __seq_open_private(struct linux_file *f, const struct seq_operations *op, int size) 209 { 210 struct seq_file *seq_file; 211 void *private; 212 int error; 213 214 private = malloc(size, M_LSEQ, M_NOWAIT|M_ZERO); 215 if (private == NULL) 216 return (NULL); 217 218 error = seq_open(f, op); 219 if (error < 0) { 220 free(private, M_LSEQ); 221 return (NULL); 222 } 223 224 seq_file = (struct seq_file *)f->private_data; 225 seq_file->private = private; 226 227 return (private); 228 } 229 230 static int 231 _single_open_without_sbuf(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d) 232 { 233 struct seq_operations *op; 234 int rc = -ENOMEM; 235 236 op = malloc(sizeof(*op), M_LSEQ, M_NOWAIT); 237 if (op) { 238 op->start = single_start; 239 op->next = single_next; 240 op->stop = single_stop; 241 op->show = show; 242 rc = _seq_open_without_sbuf(f, op); 243 if (rc) 244 free(op, M_LSEQ); 245 else 246 ((struct seq_file *)f->private_data)->private = d; 247 } 248 return (rc); 249 } 250 251 int 252 single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d) 253 { 254 int ret; 255 256 ret = _single_open_without_sbuf(f, show, d); 257 if (ret == 0) 258 ((struct seq_file *)f->private_data)->buf = sbuf_new_auto(); 259 260 return (ret); 261 } 262 263 int 264 single_open_size(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d, size_t size) 265 { 266 int ret; 267 268 ret = _single_open_without_sbuf(f, show, d); 269 if (ret == 0) 270 ((struct seq_file *)f->private_data)->buf = sbuf_new( 271 NULL, NULL, size, SBUF_AUTOEXTEND); 272 273 return (ret); 274 } 275 276 int 277 seq_release(struct inode *inode __unused, struct linux_file *file) 278 { 279 struct seq_file *m; 280 struct sbuf *s; 281 282 m = file->private_data; 283 s = m->buf; 284 285 sbuf_delete(s); 286 free(m, M_LSEQ); 287 288 return (0); 289 } 290 291 int 292 seq_release_private(struct inode *inode __unused, struct linux_file *f) 293 { 294 struct seq_file *seq; 295 296 seq = (struct seq_file *)f->private_data; 297 free(seq->private, M_LSEQ); 298 return (seq_release(inode, f)); 299 } 300 301 int 302 single_release(struct vnode *v, struct linux_file *f) 303 { 304 const struct seq_operations *op; 305 struct seq_file *m; 306 int rc; 307 308 /* be NULL safe */ 309 if ((m = f->private_data) == NULL) 310 return (0); 311 312 op = m->op; 313 rc = seq_release(v, f); 314 free(__DECONST(void *, op), M_LSEQ); 315 return (rc); 316 } 317 318 void 319 lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args) 320 { 321 int ret; 322 323 ret = sbuf_vprintf(m->buf, fmt, args); 324 if (ret == 0) 325 m->size = sbuf_len(m->buf); 326 } 327 328 void 329 lkpi_seq_printf(struct seq_file *m, const char *fmt, ...) 330 { 331 va_list args; 332 333 va_start(args, fmt); 334 lkpi_seq_vprintf(m, fmt, args); 335 va_end(args); 336 } 337 338 bool 339 seq_has_overflowed(struct seq_file *m) 340 { 341 return (sbuf_len(m->buf) == -1); 342 } 343