1 /* $NetBSD: readhappy.c,v 1.1 2015/05/13 07:07:36 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: readhappy.c,v 1.1 2015/05/13 07:07:36 pgoyette Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/conf.h> 34 #include <sys/device.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 38 /* 39 * Create a device /dev/happy from which you can read sequential 40 * happy numbers. 41 * 42 * To use this device you need to do: 43 * mknod /dev/happy c 210 0 44 * 45 * Commentary: 46 * A happy number is a number defined by the following process: Starting with 47 * any positive integer, replace the number by the sum of the squares of its 48 * digits, and repeat the process until the number equals 1 (where it will 49 * stay), or it loops endlessly in a cycle which does not include 1. Those 50 * numbers for which this process ends in 1 are happy numbers, while those that 51 * do not end in 1 are unhappy numbers (or sad numbers). 52 * 53 * For more information on happy numbers, and the algorithms, see 54 * http://en.wikipedia.org/wiki/Happy_number 55 * 56 * The happy number generator is here only to have something that the user 57 * can read from our device. Any other arbitrary data generator could 58 * have been used. The algorithm is not critical to the implementation 59 * of the module. 60 */ 61 62 63 #define HAPPY_NUMBER 1 64 65 /* If n is not happy then its sequence ends in the cycle: 66 * 4, 16, 37, 58, 89, 145, 42, 20, 4, ... */ 67 #define SAD_NUMBER 4 68 69 /* Calculate the sum of the squares of the digits of n */ 70 static unsigned 71 dsum(unsigned n) 72 { 73 unsigned sum, x; 74 for (sum = 0; n; n /= 10) { 75 x = n % 10; 76 sum += x * x; 77 } 78 return sum; 79 } 80 81 static int 82 check_happy(unsigned n) 83 { 84 for (;;) { 85 unsigned total = dsum(n); 86 87 if (total == HAPPY_NUMBER) 88 return 1; 89 if (total == SAD_NUMBER) 90 return 0; 91 92 n = total; 93 } 94 } 95 96 dev_type_open(happy_open); 97 dev_type_close(happy_close); 98 dev_type_read(happy_read); 99 100 static struct cdevsw happy_cdevsw = { 101 .d_open = happy_open, 102 .d_close = happy_close, 103 .d_read = happy_read, 104 .d_write = nowrite, 105 .d_ioctl = noioctl, 106 .d_stop = nostop, 107 .d_tty = notty, 108 .d_poll = nopoll, 109 .d_mmap = nommap, 110 .d_kqfilter = nokqfilter, 111 .d_discard = nodiscard, 112 .d_flag = D_OTHER 113 }; 114 115 116 struct happy_softc { 117 int refcnt; 118 unsigned last; 119 }; 120 121 static struct happy_softc sc; 122 123 int 124 happy_open(dev_t self __unused, int flag __unused, int mode __unused, 125 struct lwp *l __unused) 126 { 127 if (sc.refcnt > 0) 128 return EBUSY; 129 130 sc.last = 0; 131 ++sc.refcnt; 132 133 return 0; 134 } 135 136 int 137 happy_close(dev_t self __unused, int flag __unused, int mode __unused, 138 struct lwp *l __unused) 139 { 140 --sc.refcnt; 141 142 return 0; 143 } 144 145 int 146 happy_read(dev_t self __unused, struct uio *uio, int flags __unused) 147 { 148 char line[80]; 149 150 /* Get next happy number */ 151 while (check_happy(++sc.last) == 0) 152 continue; 153 154 /* Print it into line[] with trailing \n */ 155 int len = snprintf(line, sizeof(line), "%u\n", sc.last); 156 157 /* Is there room? */ 158 if (uio->uio_resid < len) { 159 --sc.last; /* Step back */ 160 return EINVAL; 161 } 162 163 /* Send it to User-Space */ 164 int e; 165 if ((e = uiomove(line, len, uio))) 166 return e; 167 168 return 0; 169 } 170 171 MODULE(MODULE_CLASS_MISC, happy, NULL); 172 173 static int 174 happy_modcmd(modcmd_t cmd, void *arg __unused) 175 { 176 /* The major should be verified and changed if needed to avoid 177 * conflicts with other devices. */ 178 int cmajor = 210, bmajor = -1; 179 180 switch (cmd) { 181 case MODULE_CMD_INIT: 182 if (devsw_attach("happy", NULL, &bmajor, &happy_cdevsw, 183 &cmajor)) 184 return ENXIO; 185 return 0; 186 case MODULE_CMD_FINI: 187 if (sc.refcnt > 0) 188 return EBUSY; 189 190 devsw_detach(NULL, &happy_cdevsw); 191 return 0; 192 default: 193 return ENOTTY; 194 } 195 } 196