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