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