xref: /freebsd/sys/dev/null/null.c (revision e140d551b78670fbf99c83a59438cb13de50420f)
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$");
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). */
50  static struct cdev *full_dev;
51  static struct cdev *null_dev;
52  static struct cdev *zero_dev;
53  
54  static d_write_t full_write;
55  static d_write_t null_write;
56  static d_ioctl_t null_ioctl;
57  static d_ioctl_t zero_ioctl;
58  static d_read_t zero_read;
59  
60  static 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  
68  static 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  
76  static 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  /* ARGSUSED */
86  static int
87  full_write(struct cdev *dev __unused, struct uio *uio __unused, int flags __unused)
88  {
89  
90  	return (ENOSPC);
91  }
92  
93  /* ARGSUSED */
94  static int
95  null_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
96  {
97  	uio->uio_resid = 0;
98  
99  	return (0);
100  }
101  
102  /* ARGSUSED */
103  static int
104  null_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data __unused,
105      int flags __unused, struct thread *td)
106  {
107  	struct diocskerneldump_arg kda;
108  	int error;
109  
110  	error = 0;
111  	switch (cmd) {
112  	case DIOCSKERNELDUMP:
113  		bzero(&kda, sizeof(kda));
114  		kda.kda_index = KDA_REMOVE_ALL;
115  		error = dumper_remove(NULL, &kda);
116  		break;
117  	case FIONBIO:
118  		break;
119  	case FIOASYNC:
120  		if (*(int *)data != 0)
121  			error = EINVAL;
122  		break;
123  	default:
124  		error = ENOIOCTL;
125  	}
126  	return (error);
127  }
128  
129  /* ARGSUSED */
130  static int
131  zero_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data __unused,
132  	   int flags __unused, struct thread *td)
133  {
134  	int error;
135  	error = 0;
136  
137  	switch (cmd) {
138  	case FIONBIO:
139  		break;
140  	case FIOASYNC:
141  		if (*(int *)data != 0)
142  			error = EINVAL;
143  		break;
144  	default:
145  		error = ENOIOCTL;
146  	}
147  	return (error);
148  }
149  
150  /* ARGSUSED */
151  static int
152  zero_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 */
172  static int
173  null_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  
203  DEV_MODULE(null, null_modevent, NULL);
204  MODULE_VERSION(null, 1);
205