null.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2000 Mark R. V. Murray & Jeroen C. van Gelderen
5 * Copyright (c) 2001-2004 Mark R. V. Murray
6 * Copyright (c) 2014 Eitan Adler
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer
14 *    in this position and unchanged.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: stable/11/sys/dev/null/null.c 330897 2018-03-14 03:19:51Z eadler $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/conf.h>
38#include <sys/uio.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/module.h>
42#include <sys/disk.h>
43#include <sys/bus.h>
44#include <sys/filio.h>
45
46#include <machine/bus.h>
47#include <machine/vmparam.h>
48
49/* For use with destroy_dev(9). */
50static struct cdev *full_dev;
51static struct cdev *null_dev;
52static struct cdev *zero_dev;
53
54static d_write_t full_write;
55static d_write_t null_write;
56static d_ioctl_t null_ioctl;
57static d_ioctl_t zero_ioctl;
58static d_read_t zero_read;
59
60static struct cdevsw full_cdevsw = {
61	.d_version =	D_VERSION,
62	.d_read =	zero_read,
63	.d_write =	full_write,
64	.d_ioctl =	zero_ioctl,
65	.d_name =	"full",
66};
67
68static struct cdevsw null_cdevsw = {
69	.d_version =	D_VERSION,
70	.d_read =	(d_read_t *)nullop,
71	.d_write =	null_write,
72	.d_ioctl =	null_ioctl,
73	.d_name =	"null",
74};
75
76static struct cdevsw zero_cdevsw = {
77	.d_version =	D_VERSION,
78	.d_read =	zero_read,
79	.d_write =	null_write,
80	.d_ioctl =	zero_ioctl,
81	.d_name =	"zero",
82	.d_flags =	D_MMAP_ANON,
83};
84
85
86
87/* ARGSUSED */
88static int
89full_write(struct cdev *dev __unused, struct uio *uio __unused, int flags __unused)
90{
91
92	return (ENOSPC);
93}
94
95/* ARGSUSED */
96static int
97null_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
98{
99	uio->uio_resid = 0;
100
101	return (0);
102}
103
104/* ARGSUSED */
105static int
106null_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data __unused,
107    int flags __unused, struct thread *td)
108{
109	int error;
110	error = 0;
111
112	switch (cmd) {
113	case DIOCSKERNELDUMP:
114		error = set_dumper(NULL, NULL, td);
115		break;
116	case FIONBIO:
117		break;
118	case FIOASYNC:
119		if (*(int *)data != 0)
120			error = EINVAL;
121		break;
122	default:
123		error = ENOIOCTL;
124	}
125	return (error);
126}
127
128/* ARGSUSED */
129static int
130zero_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data __unused,
131	   int flags __unused, struct thread *td)
132{
133	int error;
134	error = 0;
135
136	switch (cmd) {
137	case FIONBIO:
138		break;
139	case FIOASYNC:
140		if (*(int *)data != 0)
141			error = EINVAL;
142		break;
143	default:
144		error = ENOIOCTL;
145	}
146	return (error);
147}
148
149
150/* ARGSUSED */
151static int
152zero_read(struct cdev *dev __unused, struct uio *uio, int flags __unused)
153{
154	void *zbuf;
155	ssize_t len;
156	int error = 0;
157
158	KASSERT(uio->uio_rw == UIO_READ,
159	    ("Can't be in %s for write", __func__));
160	zbuf = __DECONST(void *, zero_region);
161	while (uio->uio_resid > 0 && error == 0) {
162		len = uio->uio_resid;
163		if (len > ZERO_REGION_SIZE)
164			len = ZERO_REGION_SIZE;
165		error = uiomove(zbuf, len, uio);
166	}
167
168	return (error);
169}
170
171/* ARGSUSED */
172static int
173null_modevent(module_t mod __unused, int type, void *data __unused)
174{
175	switch(type) {
176	case MOD_LOAD:
177		if (bootverbose)
178			printf("null: <full device, null device, zero device>\n");
179		full_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &full_cdevsw, 0,
180		    NULL, UID_ROOT, GID_WHEEL, 0666, "full");
181		null_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &null_cdevsw, 0,
182		    NULL, UID_ROOT, GID_WHEEL, 0666, "null");
183		zero_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &zero_cdevsw, 0,
184		    NULL, UID_ROOT, GID_WHEEL, 0666, "zero");
185		break;
186
187	case MOD_UNLOAD:
188		destroy_dev(full_dev);
189		destroy_dev(null_dev);
190		destroy_dev(zero_dev);
191		break;
192
193	case MOD_SHUTDOWN:
194		break;
195
196	default:
197		return (EOPNOTSUPP);
198	}
199
200	return (0);
201}
202
203DEV_MODULE(null, null_modevent, NULL);
204MODULE_VERSION(null, 1);
205