1/* $NetBSD: luareadhappy.c,v 1.2 2020/01/30 07:58:33 kamil 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: luareadhappy.c,v 1.2 2020/01/30 07:58:33 kamil 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/lua.h> 37#include <sys/module.h> 38#include <lua.h> 39 40/* 41 * Create a device /dev/happy from which you can read sequential 42 * happy numbers. 43 * 44 * To use this device you need to do: 45 * mknod /dev/happy c 351 0 46 * 47 * Commentary: 48 * A happy number is a number defined by the following process: Starting with 49 * any positive integer, replace the number by the sum of the squares of its 50 * digits, and repeat the process until the number equals 1 (where it will 51 * stay), or it loops endlessly in a cycle which does not include 1. Those 52 * numbers for which this process ends in 1 are happy numbers, while those that 53 * do not end in 1 are unhappy numbers (or sad numbers). 54 * 55 * For more information on happy numbers, and the algorithms, see 56 * http://en.wikipedia.org/wiki/Happy_number 57 * 58 * The happy number generator is here only to have something that the user 59 * can read from our device. Any other arbitrary data generator could 60 * have been used. The algorithm is not critical to the implementation 61 * of the module. 62 */ 63 64dev_type_open(happy_open); 65dev_type_close(happy_close); 66dev_type_read(happy_read); 67 68static struct cdevsw happy_cdevsw = { 69 .d_open = happy_open, 70 .d_close = happy_close, 71 .d_read = happy_read, 72 .d_write = nowrite, 73 .d_ioctl = noioctl, 74 .d_stop = nostop, 75 .d_tty = notty, 76 .d_poll = nopoll, 77 .d_mmap = nommap, 78 .d_kqfilter = nokqfilter, 79 .d_discard = nodiscard, 80 .d_flag = D_OTHER 81}; 82 83 84struct happy_softc { 85 int refcnt; 86 unsigned last; 87 klua_State *kL; 88}; 89 90static struct happy_softc sc; 91 92/* Function that calls a Lua routine and returns whether a number is happy */ 93static int 94check_happy(unsigned n) 95{ 96 int rv; 97 98 klua_lock(sc.kL); 99 lua_getglobal(sc.kL->L, "is_happy"); 100 101 if (!lua_isfunction(sc.kL->L, -1)) { 102 lua_pop(sc.kL->L, 1); 103 klua_unlock(sc.kL); 104 return -1; 105 } 106 107 lua_pushnumber(sc.kL->L, n); 108 if (lua_pcall(sc.kL->L, 1 /* args */, 1 /* res */, 0) != 0) { 109 lua_pop(sc.kL->L, 2); 110 klua_unlock(sc.kL); 111 return -1; 112 } 113 114 if (!lua_isnumber(sc.kL->L, -1)) { 115 lua_pop(sc.kL->L, 1); 116 klua_unlock(sc.kL); 117 return -1; 118 } 119 120 rv = lua_tointeger(sc.kL->L, -1); 121 122 lua_pop(sc.kL->L, 1); 123 klua_unlock(sc.kL); 124 125 /* Consistency check */ 126 if (rv != 0 && rv != 1) 127 rv = -1; 128 129 return rv; 130} 131 132int 133happy_open(dev_t self __unused, int flag __unused, int mode __unused, 134 struct lwp *l __unused) 135{ 136 if (sc.refcnt > 0) 137 return EBUSY; 138 139 sc.last = 0; 140 ++sc.refcnt; 141 142 return 0; 143} 144 145int 146happy_close(dev_t self __unused, int flag __unused, int mode __unused, 147 struct lwp *l __unused) 148{ 149 --sc.refcnt; 150 151 return 0; 152} 153 154int 155happy_read(dev_t self __unused, struct uio *uio, int flags __unused) 156{ 157 int rv; 158 char line[80]; 159 160 /* Get next happy number */ 161 while ((rv = check_happy(++sc.last)) == 0) 162 continue; 163 164 /* Something went wrong */ 165 if (rv == -1) 166 return ECANCELED; 167 168 /* Print it into line[] with trailing \n */ 169 int len = snprintf(line, sizeof(line), "%u\n", sc.last); 170 171 /* Is there room? */ 172 if (uio->uio_resid < len) { 173 --sc.last; /* Step back */ 174 return EINVAL; 175 } 176 177 /* Send it to User-Space */ 178 int e; 179 if ((e = uiomove(line, len, uio))) 180 return e; 181 182 return 0; 183} 184 185MODULE(MODULE_CLASS_MISC, happy, "lua"); 186 187static int 188happy_modcmd(modcmd_t cmd, void *arg __unused) 189{ 190 /* The major should be verified and changed if needed to avoid 191 * conflicts with other devices. */ 192 int cmajor = 351, bmajor = -1; 193 194 switch (cmd) { 195 case MODULE_CMD_INIT: 196 if (devsw_attach("happy", NULL, &bmajor, &happy_cdevsw, 197 &cmajor)) 198 return ENXIO; 199 if ((sc.kL = kluaL_newstate("happy", 200 "Example Happy Number calculator", 201 IPL_NONE)) == NULL) { 202 devsw_detach(NULL, &happy_cdevsw); 203 return ENXIO; 204 } 205 return 0; 206 case MODULE_CMD_FINI: 207 if (sc.refcnt > 0) 208 return EBUSY; 209 210 klua_close(sc.kL); 211 212 devsw_detach(NULL, &happy_cdevsw); 213 return 0; 214 default: 215 return ENOTTY; 216 } 217} 218