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