Home | History | Annotate | Line # | Download | only in kern
kern_hook.c revision 1.1
      1 /*	$NetBSD: kern_hook.c,v 1.1 2010/01/31 01:38:48 pooka Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center, and by Luke Mewburn.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.1 2010/01/31 01:38:48 pooka Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/malloc.h>
     38 #include <sys/rwlock.h>
     39 #include <sys/systm.h>
     40 
     41 /*
     42  * A generic linear hook.
     43  */
     44 struct hook_desc {
     45 	LIST_ENTRY(hook_desc) hk_list;
     46 	void	(*hk_fn)(void *);
     47 	void	*hk_arg;
     48 };
     49 typedef LIST_HEAD(, hook_desc) hook_list_t;
     50 
     51 int	powerhook_debug = 0;
     52 
     53 static void *
     54 hook_establish(hook_list_t *list, void (*fn)(void *), void *arg)
     55 {
     56 	struct hook_desc *hd;
     57 
     58 	hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT);
     59 	if (hd == NULL)
     60 		return (NULL);
     61 
     62 	hd->hk_fn = fn;
     63 	hd->hk_arg = arg;
     64 	LIST_INSERT_HEAD(list, hd, hk_list);
     65 
     66 	return (hd);
     67 }
     68 
     69 static void
     70 hook_disestablish(hook_list_t *list, void *vhook)
     71 {
     72 #ifdef DIAGNOSTIC
     73 	struct hook_desc *hd;
     74 
     75 	LIST_FOREACH(hd, list, hk_list) {
     76                 if (hd == vhook)
     77 			break;
     78 	}
     79 
     80 	if (hd == NULL)
     81 		panic("hook_disestablish: hook %p not established", vhook);
     82 #endif
     83 	LIST_REMOVE((struct hook_desc *)vhook, hk_list);
     84 	free(vhook, M_DEVBUF);
     85 }
     86 
     87 static void
     88 hook_destroy(hook_list_t *list)
     89 {
     90 	struct hook_desc *hd;
     91 
     92 	while ((hd = LIST_FIRST(list)) != NULL) {
     93 		LIST_REMOVE(hd, hk_list);
     94 		free(hd, M_DEVBUF);
     95 	}
     96 }
     97 
     98 static void
     99 hook_proc_run(hook_list_t *list, struct proc *p)
    100 {
    101 	struct hook_desc *hd;
    102 
    103 	LIST_FOREACH(hd, list, hk_list)
    104 		((void (*)(struct proc *, void *))*hd->hk_fn)(p, hd->hk_arg);
    105 }
    106 
    107 /*
    108  * "Shutdown hook" types, functions, and variables.
    109  *
    110  * Should be invoked immediately before the
    111  * system is halted or rebooted, i.e. after file systems unmounted,
    112  * after crash dump done, etc.
    113  *
    114  * Each shutdown hook is removed from the list before it's run, so that
    115  * it won't be run again.
    116  */
    117 
    118 static hook_list_t shutdownhook_list = LIST_HEAD_INITIALIZER(shutdownhook_list);
    119 
    120 void *
    121 shutdownhook_establish(void (*fn)(void *), void *arg)
    122 {
    123 	return hook_establish(&shutdownhook_list, fn, arg);
    124 }
    125 
    126 void
    127 shutdownhook_disestablish(void *vhook)
    128 {
    129 	hook_disestablish(&shutdownhook_list, vhook);
    130 }
    131 
    132 /*
    133  * Run shutdown hooks.  Should be invoked immediately before the
    134  * system is halted or rebooted, i.e. after file systems unmounted,
    135  * after crash dump done, etc.
    136  *
    137  * Each shutdown hook is removed from the list before it's run, so that
    138  * it won't be run again.
    139  */
    140 void
    141 doshutdownhooks(void)
    142 {
    143 	struct hook_desc *dp;
    144 
    145 	while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) {
    146 		LIST_REMOVE(dp, hk_list);
    147 		(*dp->hk_fn)(dp->hk_arg);
    148 #if 0
    149 		/*
    150 		 * Don't bother freeing the hook structure,, since we may
    151 		 * be rebooting because of a memory corruption problem,
    152 		 * and this might only make things worse.  It doesn't
    153 		 * matter, anyway, since the system is just about to
    154 		 * reboot.
    155 		 */
    156 		free(dp, M_DEVBUF);
    157 #endif
    158 	}
    159 }
    160 
    161 /*
    162  * "Mountroot hook" types, functions, and variables.
    163  */
    164 
    165 static hook_list_t mountroothook_list=LIST_HEAD_INITIALIZER(mountroothook_list);
    166 
    167 void *
    168 mountroothook_establish(void (*fn)(device_t), device_t dev)
    169 {
    170 	return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev);
    171 }
    172 
    173 void
    174 mountroothook_disestablish(void *vhook)
    175 {
    176 	hook_disestablish(&mountroothook_list, vhook);
    177 }
    178 
    179 void
    180 mountroothook_destroy(void)
    181 {
    182 	hook_destroy(&mountroothook_list);
    183 }
    184 
    185 void
    186 domountroothook(void)
    187 {
    188 	struct hook_desc *hd;
    189 
    190 	LIST_FOREACH(hd, &mountroothook_list, hk_list) {
    191 		if (hd->hk_arg == (void *)root_device) {
    192 			(*hd->hk_fn)(hd->hk_arg);
    193 			return;
    194 		}
    195 	}
    196 }
    197 
    198 static hook_list_t exechook_list = LIST_HEAD_INITIALIZER(exechook_list);
    199 
    200 void *
    201 exechook_establish(void (*fn)(struct proc *, void *), void *arg)
    202 {
    203 	return hook_establish(&exechook_list, (void (*)(void *))fn, arg);
    204 }
    205 
    206 void
    207 exechook_disestablish(void *vhook)
    208 {
    209 	hook_disestablish(&exechook_list, vhook);
    210 }
    211 
    212 /*
    213  * Run exec hooks.
    214  */
    215 void
    216 doexechooks(struct proc *p)
    217 {
    218 	hook_proc_run(&exechook_list, p);
    219 }
    220 
    221 static hook_list_t exithook_list = LIST_HEAD_INITIALIZER(exithook_list);
    222 extern krwlock_t exec_lock;
    223 
    224 void *
    225 exithook_establish(void (*fn)(struct proc *, void *), void *arg)
    226 {
    227 	void *rv;
    228 
    229 	rw_enter(&exec_lock, RW_WRITER);
    230 	rv = hook_establish(&exithook_list, (void (*)(void *))fn, arg);
    231 	rw_exit(&exec_lock);
    232 	return rv;
    233 }
    234 
    235 void
    236 exithook_disestablish(void *vhook)
    237 {
    238 
    239 	rw_enter(&exec_lock, RW_WRITER);
    240 	hook_disestablish(&exithook_list, vhook);
    241 	rw_exit(&exec_lock);
    242 }
    243 
    244 /*
    245  * Run exit hooks.
    246  */
    247 void
    248 doexithooks(struct proc *p)
    249 {
    250 	hook_proc_run(&exithook_list, p);
    251 }
    252 
    253 static hook_list_t forkhook_list = LIST_HEAD_INITIALIZER(forkhook_list);
    254 
    255 void *
    256 forkhook_establish(void (*fn)(struct proc *, struct proc *))
    257 {
    258 	return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL);
    259 }
    260 
    261 void
    262 forkhook_disestablish(void *vhook)
    263 {
    264 	hook_disestablish(&forkhook_list, vhook);
    265 }
    266 
    267 /*
    268  * Run fork hooks.
    269  */
    270 void
    271 doforkhooks(struct proc *p2, struct proc *p1)
    272 {
    273 	struct hook_desc *hd;
    274 
    275 	LIST_FOREACH(hd, &forkhook_list, hk_list) {
    276 		((void (*)(struct proc *, struct proc *))*hd->hk_fn)
    277 		    (p2, p1);
    278 	}
    279 }
    280 
    281 /*
    282  * "Power hook" types, functions, and variables.
    283  * The list of power hooks is kept ordered with the last registered hook
    284  * first.
    285  * When running the hooks on power down the hooks are called in reverse
    286  * registration order, when powering up in registration order.
    287  */
    288 struct powerhook_desc {
    289 	CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
    290 	void	(*sfd_fn)(int, void *);
    291 	void	*sfd_arg;
    292 	char	sfd_name[16];
    293 };
    294 
    295 static CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
    296     CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
    297 
    298 void *
    299 powerhook_establish(const char *name, void (*fn)(int, void *), void *arg)
    300 {
    301 	struct powerhook_desc *ndp;
    302 
    303 	ndp = (struct powerhook_desc *)
    304 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
    305 	if (ndp == NULL)
    306 		return (NULL);
    307 
    308 	ndp->sfd_fn = fn;
    309 	ndp->sfd_arg = arg;
    310 	strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name));
    311 	CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
    312 
    313 	aprint_error("%s: WARNING: powerhook_establish is deprecated\n", name);
    314 	return (ndp);
    315 }
    316 
    317 void
    318 powerhook_disestablish(void *vhook)
    319 {
    320 #ifdef DIAGNOSTIC
    321 	struct powerhook_desc *dp;
    322 
    323 	CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
    324                 if (dp == vhook)
    325 			goto found;
    326 	panic("powerhook_disestablish: hook %p not established", vhook);
    327  found:
    328 #endif
    329 
    330 	CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
    331 	    sfd_list);
    332 	free(vhook, M_DEVBUF);
    333 }
    334 
    335 /*
    336  * Run power hooks.
    337  */
    338 void
    339 dopowerhooks(int why)
    340 {
    341 	struct powerhook_desc *dp;
    342 	const char *why_name;
    343 	static const char * pwr_names[] = {PWR_NAMES};
    344 	why_name = why < __arraycount(pwr_names) ? pwr_names[why] : "???";
    345 
    346 	if (why == PWR_RESUME || why == PWR_SOFTRESUME) {
    347 		CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
    348 			if (powerhook_debug)
    349 				printf("dopowerhooks %s: %s (%p)\n",
    350 				    why_name, dp->sfd_name, dp);
    351 			(*dp->sfd_fn)(why, dp->sfd_arg);
    352 		}
    353 	} else {
    354 		CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
    355 			if (powerhook_debug)
    356 				printf("dopowerhooks %s: %s (%p)\n",
    357 				    why_name, dp->sfd_name, dp);
    358 			(*dp->sfd_fn)(why, dp->sfd_arg);
    359 		}
    360 	}
    361 
    362 	if (powerhook_debug)
    363 		printf("dopowerhooks: %s done\n", why_name);
    364 }
    365