The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_subr.c,v 1.150.2.1 2007/05/13 10:28:37 jdc Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 1997, 1998, 1999, 2002 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  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Copyright (c) 1982, 1986, 1991, 1993
   42  *      The Regents of the University of California.  All rights reserved.
   43  * (c) UNIX System Laboratories, Inc.
   44  * All or some portions of this file are derived from material licensed
   45  * to the University of California by American Telephone and Telegraph
   46  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   47  * the permission of UNIX System Laboratories, Inc.
   48  *
   49  * Copyright (c) 1992, 1993
   50  *      The Regents of the University of California.  All rights reserved.
   51  *
   52  * This software was developed by the Computer Systems Engineering group
   53  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   54  * contributed to Berkeley.
   55  *
   56  * All advertising materials mentioning features or use of this software
   57  * must display the following acknowledgement:
   58  *      This product includes software developed by the University of
   59  *      California, Lawrence Berkeley Laboratory.
   60  *
   61  * Redistribution and use in source and binary forms, with or without
   62  * modification, are permitted provided that the following conditions
   63  * are met:
   64  * 1. Redistributions of source code must retain the above copyright
   65  *    notice, this list of conditions and the following disclaimer.
   66  * 2. Redistributions in binary form must reproduce the above copyright
   67  *    notice, this list of conditions and the following disclaimer in the
   68  *    documentation and/or other materials provided with the distribution.
   69  * 3. Neither the name of the University nor the names of its contributors
   70  *    may be used to endorse or promote products derived from this software
   71  *    without specific prior written permission.
   72  *
   73  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   74  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   75  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   76  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   77  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   78  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   79  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   80  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   81  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   82  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   83  * SUCH DAMAGE.
   84  *
   85  *      @(#)kern_subr.c 8.4 (Berkeley) 2/14/95
   86  */
   87 
   88 #include <sys/cdefs.h>
   89 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.150.2.1 2007/05/13 10:28:37 jdc Exp $");
   90 
   91 #include "opt_ddb.h"
   92 #include "opt_md.h"
   93 #include "opt_syscall_debug.h"
   94 #include "opt_ktrace.h"
   95 #include "opt_ptrace.h"
   96 #include "opt_systrace.h"
   97 #include "opt_powerhook.h"
   98 #include "opt_tftproot.h"
   99 
  100 #include <sys/param.h>
  101 #include <sys/systm.h>
  102 #include <sys/proc.h>
  103 #include <sys/malloc.h>
  104 #include <sys/mount.h>
  105 #include <sys/device.h>
  106 #include <sys/reboot.h>
  107 #include <sys/conf.h>
  108 #include <sys/disklabel.h>
  109 #include <sys/queue.h>
  110 #include <sys/systrace.h>
  111 #include <sys/ktrace.h>
  112 #include <sys/ptrace.h>
  113 #include <sys/fcntl.h>
  114 
  115 #include <uvm/uvm_extern.h>
  116 
  117 #include <dev/cons.h>
  118 
  119 #include <net/if.h>
  120 
  121 /* XXX these should eventually move to subr_autoconf.c */
  122 static struct device *finddevice(const char *);
  123 static struct device *getdisk(char *, int, int, dev_t *, int);
  124 static struct device *parsedisk(char *, int, int, dev_t *);
  125 
  126 /*
  127  * A generic linear hook.
  128  */
  129 struct hook_desc {
  130         LIST_ENTRY(hook_desc) hk_list;
  131         void    (*hk_fn)(void *);
  132         void    *hk_arg;
  133 };
  134 typedef LIST_HEAD(, hook_desc) hook_list_t;
  135 
  136 MALLOC_DEFINE(M_IOV, "iov", "large iov's");
  137 
  138 #ifdef TFTPROOT
  139 int tftproot_dhcpboot(struct device *);
  140 #endif
  141 
  142 void
  143 uio_setup_sysspace(struct uio *uio)
  144 {
  145 
  146         uio->uio_vmspace = vmspace_kernel();
  147 }
  148 
  149 int
  150 uiomove(void *buf, size_t n, struct uio *uio)
  151 {
  152         struct vmspace *vm = uio->uio_vmspace;
  153         struct iovec *iov;
  154         u_int cnt;
  155         int error = 0;
  156         char *cp = buf;
  157         int hold_count;
  158 
  159         hold_count = KERNEL_LOCK_RELEASE_ALL();
  160 
  161         ASSERT_SLEEPABLE(NULL, "uiomove");
  162 
  163 #ifdef DIAGNOSTIC
  164         if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
  165                 panic("uiomove: mode");
  166 #endif
  167         while (n > 0 && uio->uio_resid) {
  168                 iov = uio->uio_iov;
  169                 cnt = iov->iov_len;
  170                 if (cnt == 0) {
  171                         KASSERT(uio->uio_iovcnt > 0);
  172                         uio->uio_iov++;
  173                         uio->uio_iovcnt--;
  174                         continue;
  175                 }
  176                 if (cnt > n)
  177                         cnt = n;
  178                 if (!VMSPACE_IS_KERNEL_P(vm)) {
  179                         if (curcpu()->ci_schedstate.spc_flags &
  180                             SPCF_SHOULDYIELD)
  181                                 preempt(1);
  182                 }
  183 
  184                 if (uio->uio_rw == UIO_READ) {
  185                         error = copyout_vmspace(vm, cp, iov->iov_base,
  186                             cnt);
  187                 } else {
  188                         error = copyin_vmspace(vm, iov->iov_base, cp,
  189                             cnt);
  190                 }
  191                 if (error) {
  192                         break;
  193                 }
  194                 iov->iov_base = (caddr_t)iov->iov_base + cnt;
  195                 iov->iov_len -= cnt;
  196                 uio->uio_resid -= cnt;
  197                 uio->uio_offset += cnt;
  198                 cp += cnt;
  199                 KDASSERT(cnt <= n);
  200                 n -= cnt;
  201         }
  202         KERNEL_LOCK_ACQUIRE_COUNT(hold_count);
  203         return (error);
  204 }
  205 
  206 /*
  207  * Wrapper for uiomove() that validates the arguments against a known-good
  208  * kernel buffer.
  209  */
  210 int
  211 uiomove_frombuf(void *buf, size_t buflen, struct uio *uio)
  212 {
  213         size_t offset;
  214 
  215         if (uio->uio_offset < 0 || /* uio->uio_resid < 0 || */
  216             (offset = uio->uio_offset) != uio->uio_offset)
  217                 return (EINVAL);
  218         if (offset >= buflen)
  219                 return (0);
  220         return (uiomove((char *)buf + offset, buflen - offset, uio));
  221 }
  222 
  223 /*
  224  * Give next character to user as result of read.
  225  */
  226 int
  227 ureadc(int c, struct uio *uio)
  228 {
  229         struct iovec *iov;
  230 
  231         if (uio->uio_resid <= 0)
  232                 panic("ureadc: non-positive resid");
  233 again:
  234         if (uio->uio_iovcnt <= 0)
  235                 panic("ureadc: non-positive iovcnt");
  236         iov = uio->uio_iov;
  237         if (iov->iov_len <= 0) {
  238                 uio->uio_iovcnt--;
  239                 uio->uio_iov++;
  240                 goto again;
  241         }
  242         if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace)) {
  243                 if (subyte(iov->iov_base, c) < 0)
  244                         return (EFAULT);
  245         } else {
  246                 *(char *)iov->iov_base = c;
  247         }
  248         iov->iov_base = (caddr_t)iov->iov_base + 1;
  249         iov->iov_len--;
  250         uio->uio_resid--;
  251         uio->uio_offset++;
  252         return (0);
  253 }
  254 
  255 /*
  256  * Like copyin(), but operates on an arbitrary vmspace.
  257  */
  258 int
  259 copyin_vmspace(struct vmspace *vm, const void *uaddr, void *kaddr, size_t len)
  260 {
  261         struct iovec iov;
  262         struct uio uio;
  263         int error;
  264 
  265         if (len == 0)
  266                 return (0);
  267 
  268         if (VMSPACE_IS_KERNEL_P(vm)) {
  269                 return kcopy(uaddr, kaddr, len);
  270         }
  271         if (__predict_true(vm == curproc->p_vmspace)) {
  272                 return copyin(uaddr, kaddr, len);
  273         }
  274 
  275         iov.iov_base = kaddr;
  276         iov.iov_len = len;
  277         uio.uio_iov = &iov;
  278         uio.uio_iovcnt = 1;
  279         uio.uio_offset = (off_t)(intptr_t)uaddr;
  280         uio.uio_resid = len;
  281         uio.uio_rw = UIO_READ;
  282         UIO_SETUP_SYSSPACE(&uio);
  283         error = uvm_io(&vm->vm_map, &uio);
  284 
  285         return (error);
  286 }
  287 
  288 /*
  289  * Like copyout(), but operates on an arbitrary vmspace.
  290  */
  291 int
  292 copyout_vmspace(struct vmspace *vm, const void *kaddr, void *uaddr, size_t len)
  293 {
  294         struct iovec iov;
  295         struct uio uio;
  296         int error;
  297 
  298         if (len == 0)
  299                 return (0);
  300 
  301         if (VMSPACE_IS_KERNEL_P(vm)) {
  302                 return kcopy(kaddr, uaddr, len);
  303         }
  304         if (__predict_true(vm == curproc->p_vmspace)) {
  305                 return copyout(kaddr, uaddr, len);
  306         }
  307 
  308         iov.iov_base = __UNCONST(kaddr); /* XXXUNCONST cast away const */
  309         iov.iov_len = len;
  310         uio.uio_iov = &iov;
  311         uio.uio_iovcnt = 1;
  312         uio.uio_offset = (off_t)(intptr_t)uaddr;
  313         uio.uio_resid = len;
  314         uio.uio_rw = UIO_WRITE;
  315         UIO_SETUP_SYSSPACE(&uio);
  316         error = uvm_io(&vm->vm_map, &uio);
  317 
  318         return (error);
  319 }
  320 
  321 /*
  322  * Like copyin(), but operates on an arbitrary process.
  323  */
  324 int
  325 copyin_proc(struct proc *p, const void *uaddr, void *kaddr, size_t len)
  326 {
  327         struct vmspace *vm;
  328         int error;
  329 
  330         error = proc_vmspace_getref(p, &vm);
  331         if (error) {
  332                 return error;
  333         }
  334         error = copyin_vmspace(vm, uaddr, kaddr, len);
  335         uvmspace_free(vm);
  336 
  337         return error;
  338 }
  339 
  340 /*
  341  * Like copyout(), but operates on an arbitrary process.
  342  */
  343 int
  344 copyout_proc(struct proc *p, const void *kaddr, void *uaddr, size_t len)
  345 {
  346         struct vmspace *vm;
  347         int error;
  348 
  349         error = proc_vmspace_getref(p, &vm);
  350         if (error) {
  351                 return error;
  352         }
  353         error = copyout_vmspace(vm, kaddr, uaddr, len);
  354         uvmspace_free(vm);
  355 
  356         return error;
  357 }
  358 
  359 /*
  360  * Like copyin(), except it operates on kernel addresses when the FKIOCTL
  361  * flag is passed in `ioctlflags' from the ioctl call.
  362  */
  363 int
  364 ioctl_copyin(int ioctlflags, const void *src, void *dst, size_t len)
  365 {
  366         if (ioctlflags & FKIOCTL)
  367                 return kcopy(src, dst, len);
  368         return copyin(src, dst, len);
  369 }
  370 
  371 /*
  372  * Like copyout(), except it operates on kernel addresses when the FKIOCTL
  373  * flag is passed in `ioctlflags' from the ioctl call.
  374  */
  375 int
  376 ioctl_copyout(int ioctlflags, const void *src, void *dst, size_t len)
  377 {
  378         if (ioctlflags & FKIOCTL)
  379                 return kcopy(src, dst, len);
  380         return copyout(src, dst, len);
  381 }
  382 
  383 /*
  384  * General routine to allocate a hash table.
  385  * Allocate enough memory to hold at least `elements' list-head pointers.
  386  * Return a pointer to the allocated space and set *hashmask to a pattern
  387  * suitable for masking a value to use as an index into the returned array.
  388  */
  389 void *
  390 hashinit(u_int elements, enum hashtype htype, struct malloc_type *mtype,
  391     int mflags, u_long *hashmask)
  392 {
  393         u_long hashsize, i;
  394         LIST_HEAD(, generic) *hashtbl_list;
  395         TAILQ_HEAD(, generic) *hashtbl_tailq;
  396         size_t esize;
  397         void *p;
  398 
  399         if (elements == 0)
  400                 panic("hashinit: bad cnt");
  401         for (hashsize = 1; hashsize < elements; hashsize <<= 1)
  402                 continue;
  403 
  404         switch (htype) {
  405         case HASH_LIST:
  406                 esize = sizeof(*hashtbl_list);
  407                 break;
  408         case HASH_TAILQ:
  409                 esize = sizeof(*hashtbl_tailq);
  410                 break;
  411         default:
  412 #ifdef DIAGNOSTIC
  413                 panic("hashinit: invalid table type");
  414 #else
  415                 return NULL;
  416 #endif
  417         }
  418 
  419         if ((p = malloc(hashsize * esize, mtype, mflags)) == NULL)
  420                 return (NULL);
  421 
  422         switch (htype) {
  423         case HASH_LIST:
  424                 hashtbl_list = p;
  425                 for (i = 0; i < hashsize; i++)
  426                         LIST_INIT(&hashtbl_list[i]);
  427                 break;
  428         case HASH_TAILQ:
  429                 hashtbl_tailq = p;
  430                 for (i = 0; i < hashsize; i++)
  431                         TAILQ_INIT(&hashtbl_tailq[i]);
  432                 break;
  433         }
  434         *hashmask = hashsize - 1;
  435         return (p);
  436 }
  437 
  438 /*
  439  * Free memory from hash table previosly allocated via hashinit().
  440  */
  441 void
  442 hashdone(void *hashtbl, struct malloc_type *mtype)
  443 {
  444 
  445         free(hashtbl, mtype);
  446 }
  447 
  448 
  449 static void *
  450 hook_establish(hook_list_t *list, void (*fn)(void *), void *arg)
  451 {
  452         struct hook_desc *hd;
  453 
  454         hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT);
  455         if (hd == NULL)
  456                 return (NULL);
  457 
  458         hd->hk_fn = fn;
  459         hd->hk_arg = arg;
  460         LIST_INSERT_HEAD(list, hd, hk_list);
  461 
  462         return (hd);
  463 }
  464 
  465 static void
  466 hook_disestablish(hook_list_t *list, void *vhook)
  467 {
  468 #ifdef DIAGNOSTIC
  469         struct hook_desc *hd;
  470 
  471         LIST_FOREACH(hd, list, hk_list) {
  472                 if (hd == vhook)
  473                         break;
  474         }
  475 
  476         if (hd == NULL)
  477                 panic("hook_disestablish: hook %p not established", vhook);
  478 #endif
  479         LIST_REMOVE((struct hook_desc *)vhook, hk_list);
  480         free(vhook, M_DEVBUF);
  481 }
  482 
  483 static void
  484 hook_destroy(hook_list_t *list)
  485 {
  486         struct hook_desc *hd;
  487 
  488         while ((hd = LIST_FIRST(list)) != NULL) {
  489                 LIST_REMOVE(hd, hk_list);
  490                 free(hd, M_DEVBUF);
  491         }
  492 }
  493 
  494 static void
  495 hook_proc_run(hook_list_t *list, struct proc *p)
  496 {
  497         struct hook_desc *hd;
  498 
  499         for (hd = LIST_FIRST(list); hd != NULL; hd = LIST_NEXT(hd, hk_list)) {
  500                 ((void (*)(struct proc *, void *))*hd->hk_fn)(p,
  501                     hd->hk_arg);
  502         }
  503 }
  504 
  505 /*
  506  * "Shutdown hook" types, functions, and variables.
  507  *
  508  * Should be invoked immediately before the
  509  * system is halted or rebooted, i.e. after file systems unmounted,
  510  * after crash dump done, etc.
  511  *
  512  * Each shutdown hook is removed from the list before it's run, so that
  513  * it won't be run again.
  514  */
  515 
  516 static hook_list_t shutdownhook_list;
  517 
  518 void *
  519 shutdownhook_establish(void (*fn)(void *), void *arg)
  520 {
  521         return hook_establish(&shutdownhook_list, fn, arg);
  522 }
  523 
  524 void
  525 shutdownhook_disestablish(void *vhook)
  526 {
  527         hook_disestablish(&shutdownhook_list, vhook);
  528 }
  529 
  530 /*
  531  * Run shutdown hooks.  Should be invoked immediately before the
  532  * system is halted or rebooted, i.e. after file systems unmounted,
  533  * after crash dump done, etc.
  534  *
  535  * Each shutdown hook is removed from the list before it's run, so that
  536  * it won't be run again.
  537  */
  538 void
  539 doshutdownhooks(void)
  540 {
  541         struct hook_desc *dp;
  542 
  543         while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) {
  544                 LIST_REMOVE(dp, hk_list);
  545                 (*dp->hk_fn)(dp->hk_arg);
  546 #if 0
  547                 /*
  548                  * Don't bother freeing the hook structure,, since we may
  549                  * be rebooting because of a memory corruption problem,
  550                  * and this might only make things worse.  It doesn't
  551                  * matter, anyway, since the system is just about to
  552                  * reboot.
  553                  */
  554                 free(dp, M_DEVBUF);
  555 #endif
  556         }
  557 }
  558 
  559 /*
  560  * "Mountroot hook" types, functions, and variables.
  561  */
  562 
  563 static hook_list_t mountroothook_list;
  564 
  565 void *
  566 mountroothook_establish(void (*fn)(struct device *), struct device *dev)
  567 {
  568         return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev);
  569 }
  570 
  571 void
  572 mountroothook_disestablish(void *vhook)
  573 {
  574         hook_disestablish(&mountroothook_list, vhook);
  575 }
  576 
  577 void
  578 mountroothook_destroy(void)
  579 {
  580         hook_destroy(&mountroothook_list);
  581 }
  582 
  583 void
  584 domountroothook(void)
  585 {
  586         struct hook_desc *hd;
  587 
  588         LIST_FOREACH(hd, &mountroothook_list, hk_list) {
  589                 if (hd->hk_arg == (void *)root_device) {
  590                         (*hd->hk_fn)(hd->hk_arg);
  591                         return;
  592                 }
  593         }
  594 }
  595 
  596 static hook_list_t exechook_list;
  597 
  598 void *
  599 exechook_establish(void (*fn)(struct proc *, void *), void *arg)
  600 {
  601         return hook_establish(&exechook_list, (void (*)(void *))fn, arg);
  602 }
  603 
  604 void
  605 exechook_disestablish(void *vhook)
  606 {
  607         hook_disestablish(&exechook_list, vhook);
  608 }
  609 
  610 /*
  611  * Run exec hooks.
  612  */
  613 void
  614 doexechooks(struct proc *p)
  615 {
  616         hook_proc_run(&exechook_list, p);
  617 }
  618 
  619 static hook_list_t exithook_list;
  620 
  621 void *
  622 exithook_establish(void (*fn)(struct proc *, void *), void *arg)
  623 {
  624         return hook_establish(&exithook_list, (void (*)(void *))fn, arg);
  625 }
  626 
  627 void
  628 exithook_disestablish(void *vhook)
  629 {
  630         hook_disestablish(&exithook_list, vhook);
  631 }
  632 
  633 /*
  634  * Run exit hooks.
  635  */
  636 void
  637 doexithooks(struct proc *p)
  638 {
  639         hook_proc_run(&exithook_list, p);
  640 }
  641 
  642 static hook_list_t forkhook_list;
  643 
  644 void *
  645 forkhook_establish(void (*fn)(struct proc *, struct proc *))
  646 {
  647         return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL);
  648 }
  649 
  650 void
  651 forkhook_disestablish(void *vhook)
  652 {
  653         hook_disestablish(&forkhook_list, vhook);
  654 }
  655 
  656 /*
  657  * Run fork hooks.
  658  */
  659 void
  660 doforkhooks(struct proc *p2, struct proc *p1)
  661 {
  662         struct hook_desc *hd;
  663 
  664         LIST_FOREACH(hd, &forkhook_list, hk_list) {
  665                 ((void (*)(struct proc *, struct proc *))*hd->hk_fn)
  666                     (p2, p1);
  667         }
  668 }
  669 
  670 /*
  671  * "Power hook" types, functions, and variables.
  672  * The list of power hooks is kept ordered with the last registered hook
  673  * first.
  674  * When running the hooks on power down the hooks are called in reverse
  675  * registration order, when powering up in registration order.
  676  */
  677 struct powerhook_desc {
  678         CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
  679         void    (*sfd_fn)(int, void *);
  680         void    *sfd_arg;
  681         char    sfd_name[16];
  682 };
  683 
  684 static CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
  685     CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
  686 
  687 void *
  688 powerhook_establish(const char *name, void (*fn)(int, void *), void *arg)
  689 {
  690         struct powerhook_desc *ndp;
  691 
  692         ndp = (struct powerhook_desc *)
  693             malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
  694         if (ndp == NULL)
  695                 return (NULL);
  696 
  697         ndp->sfd_fn = fn;
  698         ndp->sfd_arg = arg;
  699         strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name));
  700         CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
  701 
  702         return (ndp);
  703 }
  704 
  705 void
  706 powerhook_disestablish(void *vhook)
  707 {
  708 #ifdef DIAGNOSTIC
  709         struct powerhook_desc *dp;
  710 
  711         CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
  712                 if (dp == vhook)
  713                         goto found;
  714         panic("powerhook_disestablish: hook %p not established", vhook);
  715  found:
  716 #endif
  717 
  718         CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
  719             sfd_list);
  720         free(vhook, M_DEVBUF);
  721 }
  722 
  723 /*
  724  * Run power hooks.
  725  */
  726 void
  727 dopowerhooks(int why)
  728 {
  729         struct powerhook_desc *dp;
  730 
  731 #ifdef POWERHOOK_DEBUG
  732         printf("dopowerhooks ");
  733         switch (why) {
  734         case PWR_RESUME:
  735                 printf("resume");
  736                 break;
  737         case PWR_SOFTRESUME:
  738                 printf("softresume");
  739                 break;
  740         case PWR_SUSPEND:
  741                 printf("suspend");
  742                 break;
  743         case PWR_SOFTSUSPEND:
  744                 printf("softsuspend");
  745                 break;
  746         case PWR_STANDBY:
  747                 printf("standby");
  748                 break;
  749         }
  750         printf(":");
  751 #endif
  752 
  753         if (why == PWR_RESUME || why == PWR_SOFTRESUME) {
  754                 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
  755 #ifdef POWERHOOK_DEBUG
  756                         printf(" %s", dp->sfd_name);
  757 #endif
  758                         (*dp->sfd_fn)(why, dp->sfd_arg);
  759                 }
  760         } else {
  761                 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
  762 #ifdef POWERHOOK_DEBUG
  763                         printf(" %s", dp->sfd_name);
  764 #endif
  765                         (*dp->sfd_fn)(why, dp->sfd_arg);
  766                 }
  767         }
  768 
  769 #ifdef POWERHOOK_DEBUG
  770         printf(".\n");
  771 #endif
  772 }
  773 
  774 /*
  775  * Determine the root device and, if instructed to, the root file system.
  776  */
  777 
  778 #include "md.h"
  779 #if NMD == 0
  780 #undef MEMORY_DISK_HOOKS
  781 #endif
  782 
  783 #ifdef MEMORY_DISK_HOOKS
  784 static struct device fakemdrootdev[NMD];
  785 extern struct cfdriver md_cd;
  786 #endif
  787 
  788 #ifdef MEMORY_DISK_IS_ROOT
  789 #define BOOT_FROM_MEMORY_HOOKS 1
  790 #endif
  791 
  792 /*
  793  * The device and wedge that we booted from.  If booted_wedge is NULL,
  794  * the we might consult booted_partition.
  795  */
  796 struct device *booted_device;
  797 struct device *booted_wedge;
  798 int booted_partition;
  799 
  800 /*
  801  * Use partition letters if it's a disk class but not a wedge.
  802  * XXX Check for wedge is kinda gross.
  803  */
  804 #define DEV_USES_PARTITIONS(dv)                                         \
  805         (device_class((dv)) == DV_DISK &&                               \
  806          !device_is_a((dv), "dk"))
  807 
  808 void
  809 setroot(struct device *bootdv, int bootpartition)
  810 {
  811         struct device *dv;
  812         int len;
  813 #ifdef MEMORY_DISK_HOOKS
  814         int i;
  815 #endif
  816         dev_t nrootdev;
  817         dev_t ndumpdev = NODEV;
  818         char buf[128];
  819         const char *rootdevname;
  820         const char *dumpdevname;
  821         struct device *rootdv = NULL;           /* XXX gcc -Wuninitialized */
  822         struct device *dumpdv = NULL;
  823         struct ifnet *ifp;
  824         const char *deffsname;
  825         struct vfsops *vops;
  826 
  827 #ifdef TFTPROOT
  828         if (tftproot_dhcpboot(bootdv) != 0)
  829                 boothowto |= RB_ASKNAME;
  830 #endif
  831 
  832 #ifdef MEMORY_DISK_HOOKS
  833         for (i = 0; i < NMD; i++) {
  834                 fakemdrootdev[i].dv_class  = DV_DISK;
  835                 fakemdrootdev[i].dv_cfdata = NULL;
  836                 fakemdrootdev[i].dv_cfdriver = &md_cd;
  837                 fakemdrootdev[i].dv_unit   = i;
  838                 fakemdrootdev[i].dv_parent = NULL;
  839                 snprintf(fakemdrootdev[i].dv_xname,
  840                     sizeof(fakemdrootdev[i].dv_xname), "md%d", i);
  841         }
  842 #endif /* MEMORY_DISK_HOOKS */
  843 
  844 #ifdef MEMORY_DISK_IS_ROOT
  845         bootdv = &fakemdrootdev[0];
  846         bootpartition = 0;
  847 #endif
  848 
  849         /*
  850          * If NFS is specified as the file system, and we found
  851          * a DV_DISK boot device (or no boot device at all), then
  852          * find a reasonable network interface for "rootspec".
  853          */
  854         vops = vfs_getopsbyname("nfs");
  855         if (vops != NULL && vops->vfs_mountroot == mountroot &&
  856             rootspec == NULL &&
  857             (bootdv == NULL || device_class(bootdv) != DV_IFNET)) {
  858                 IFNET_FOREACH(ifp) {
  859                         if ((ifp->if_flags &
  860                              (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
  861                                 break;
  862                 }
  863                 if (ifp == NULL) {
  864                         /*
  865                          * Can't find a suitable interface; ask the
  866                          * user.
  867                          */
  868                         boothowto |= RB_ASKNAME;
  869                 } else {
  870                         /*
  871                          * Have a suitable interface; behave as if
  872                          * the user specified this interface.
  873                          */
  874                         rootspec = (const char *)ifp->if_xname;
  875                 }
  876         }
  877 
  878         /*
  879          * If wildcarded root and we the boot device wasn't determined,
  880          * ask the user.
  881          */
  882         if (rootspec == NULL && bootdv == NULL)
  883                 boothowto |= RB_ASKNAME;
  884 
  885  top:
  886         if (boothowto & RB_ASKNAME) {
  887                 struct device *defdumpdv;
  888 
  889                 for (;;) {
  890                         printf("root device");
  891                         if (bootdv != NULL) {
  892                                 printf(" (default %s", bootdv->dv_xname);
  893                                 if (DEV_USES_PARTITIONS(bootdv))
  894                                         printf("%c", bootpartition + 'a');
  895                                 printf(")");
  896                         }
  897                         printf(": ");
  898                         len = cngetsn(buf, sizeof(buf));
  899                         if (len == 0 && bootdv != NULL) {
  900                                 strlcpy(buf, bootdv->dv_xname, sizeof(buf));
  901                                 len = strlen(buf);
  902                         }
  903                         if (len > 0 && buf[len - 1] == '*') {
  904                                 buf[--len] = '\0';
  905                                 dv = getdisk(buf, len, 1, &nrootdev, 0);
  906                                 if (dv != NULL) {
  907                                         rootdv = dv;
  908                                         break;
  909                                 }
  910                         }
  911                         dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
  912                         if (dv != NULL) {
  913                                 rootdv = dv;
  914                                 break;
  915                         }
  916                 }
  917 
  918                 /*
  919                  * Set up the default dump device.  If root is on
  920                  * a network device, there is no default dump
  921                  * device, since we don't support dumps to the
  922                  * network.
  923                  */
  924                 if (DEV_USES_PARTITIONS(rootdv) == 0)
  925                         defdumpdv = NULL;
  926                 else
  927                         defdumpdv = rootdv;
  928 
  929                 for (;;) {
  930                         printf("dump device");
  931                         if (defdumpdv != NULL) {
  932                                 /*
  933                                  * Note, we know it's a disk if we get here.
  934                                  */
  935                                 printf(" (default %sb)", defdumpdv->dv_xname);
  936                         }
  937                         printf(": ");
  938                         len = cngetsn(buf, sizeof(buf));
  939                         if (len == 0) {
  940                                 if (defdumpdv != NULL) {
  941                                         ndumpdev = MAKEDISKDEV(major(nrootdev),
  942                                             DISKUNIT(nrootdev), 1);
  943                                 }
  944                                 dumpdv = defdumpdv;
  945                                 break;
  946                         }
  947                         if (len == 4 && strcmp(buf, "none") == 0) {
  948                                 dumpdv = NULL;
  949                                 break;
  950                         }
  951                         dv = getdisk(buf, len, 1, &ndumpdev, 1);
  952                         if (dv != NULL) {
  953                                 dumpdv = dv;
  954                                 break;
  955                         }
  956                 }
  957 
  958                 rootdev = nrootdev;
  959                 dumpdev = ndumpdev;
  960 
  961                 for (vops = LIST_FIRST(&vfs_list); vops != NULL;
  962                      vops = LIST_NEXT(vops, vfs_list)) {
  963                         if (vops->vfs_mountroot != NULL &&
  964                             vops->vfs_mountroot == mountroot)
  965                         break;
  966                 }
  967 
  968                 if (vops == NULL) {
  969                         mountroot = NULL;
  970                         deffsname = "generic";
  971                 } else
  972                         deffsname = vops->vfs_name;
  973 
  974                 for (;;) {
  975                         printf("file system (default %s): ", deffsname);
  976                         len = cngetsn(buf, sizeof(buf));
  977                         if (len == 0)
  978                                 break;
  979                         if (len == 4 && strcmp(buf, "halt") == 0)
  980                                 cpu_reboot(RB_HALT, NULL);
  981                         else if (len == 6 && strcmp(buf, "reboot") == 0)
  982                                 cpu_reboot(0, NULL);
  983 #if defined(DDB)
  984                         else if (len == 3 && strcmp(buf, "ddb") == 0) {
  985                                 console_debugger();
  986                         }
  987 #endif
  988                         else if (len == 7 && strcmp(buf, "generic") == 0) {
  989                                 mountroot = NULL;
  990                                 break;
  991                         }
  992                         vops = vfs_getopsbyname(buf);
  993                         if (vops == NULL || vops->vfs_mountroot == NULL) {
  994                                 printf("use one of: generic");
  995                                 for (vops = LIST_FIRST(&vfs_list);
  996                                      vops != NULL;
  997                                      vops = LIST_NEXT(vops, vfs_list)) {
  998                                         if (vops->vfs_mountroot != NULL)
  999                                                 printf(" %s", vops->vfs_name);
 1000                                 }
 1001 #if defined(DDB)
 1002                                 printf(" ddb");
 1003 #endif
 1004                                 printf(" halt reboot\n");
 1005                         } else {
 1006                                 mountroot = vops->vfs_mountroot;
 1007                                 break;
 1008                         }
 1009                 }
 1010 
 1011         } else if (rootspec == NULL) {
 1012                 int majdev;
 1013 
 1014                 /*
 1015                  * Wildcarded root; use the boot device.
 1016                  */
 1017                 rootdv = bootdv;
 1018 
 1019                 majdev = devsw_name2blk(bootdv->dv_xname, NULL, 0);
 1020                 if (majdev >= 0) {
 1021                         /*
 1022                          * Root is on a disk.  `bootpartition' is root,
 1023                          * unless the device does not use partitions.
 1024                          */
 1025                         if (DEV_USES_PARTITIONS(bootdv))
 1026                                 rootdev = MAKEDISKDEV(majdev,
 1027                                                       device_unit(bootdv),
 1028                                                       bootpartition);
 1029                         else
 1030                                 rootdev = makedev(majdev, device_unit(bootdv));
 1031                 }
 1032         } else {
 1033 
 1034                 /*
 1035                  * `root on <dev> ...'
 1036                  */
 1037 
 1038                 /*
 1039                  * If it's a network interface, we can bail out
 1040                  * early.
 1041                  */
 1042                 dv = finddevice(rootspec);
 1043                 if (dv != NULL && device_class(dv) == DV_IFNET) {
 1044                         rootdv = dv;
 1045                         goto haveroot;
 1046                 }
 1047 
 1048                 rootdevname = devsw_blk2name(major(rootdev));
 1049                 if (rootdevname == NULL) {
 1050                         printf("unknown device major 0x%x\n", rootdev);
 1051                         boothowto |= RB_ASKNAME;
 1052                         goto top;
 1053                 }
 1054                 memset(buf, 0, sizeof(buf));
 1055                 snprintf(buf, sizeof(buf), "%s%d", rootdevname,
 1056                     DISKUNIT(rootdev));
 1057 
 1058                 rootdv = finddevice(buf);
 1059                 if (rootdv == NULL) {
 1060                         printf("device %s (0x%x) not configured\n",
 1061                             buf, rootdev);
 1062                         boothowto |= RB_ASKNAME;
 1063                         goto top;
 1064                 }
 1065         }
 1066 
 1067  haveroot:
 1068 
 1069         root_device = rootdv;
 1070 
 1071         switch (device_class(rootdv)) {
 1072         case DV_IFNET:
 1073         case DV_DISK:
 1074                 aprint_normal("root on %s", rootdv->dv_xname);
 1075                 if (DEV_USES_PARTITIONS(rootdv))
 1076                         aprint_normal("%c", DISKPART(rootdev) + 'a');
 1077                 break;
 1078 
 1079         default:
 1080                 printf("can't determine root device\n");
 1081                 boothowto |= RB_ASKNAME;
 1082                 goto top;
 1083         }
 1084 
 1085         /*
 1086          * Now configure the dump device.
 1087          *
 1088          * If we haven't figured out the dump device, do so, with
 1089          * the following rules:
 1090          *
 1091          *      (a) We already know dumpdv in the RB_ASKNAME case.
 1092          *
 1093          *      (b) If dumpspec is set, try to use it.  If the device
 1094          *          is not available, punt.
 1095          *
 1096          *      (c) If dumpspec is not set, the dump device is
 1097          *          wildcarded or unspecified.  If the root device
 1098          *          is DV_IFNET, punt.  Otherwise, use partition b
 1099          *          of the root device.
 1100          */
 1101 
 1102         if (boothowto & RB_ASKNAME) {           /* (a) */
 1103                 if (dumpdv == NULL)
 1104                         goto nodumpdev;
 1105         } else if (dumpspec != NULL) {          /* (b) */
 1106                 if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) {
 1107                         /*
 1108                          * Operator doesn't want a dump device.
 1109                          * Or looks like they tried to pick a network
 1110                          * device.  Oops.
 1111                          */
 1112                         goto nodumpdev;
 1113                 }
 1114 
 1115                 dumpdevname = devsw_blk2name(major(dumpdev));
 1116                 if (dumpdevname == NULL)
 1117                         goto nodumpdev;
 1118                 memset(buf, 0, sizeof(buf));
 1119                 snprintf(buf, sizeof(buf), "%s%d", dumpdevname,
 1120                     DISKUNIT(dumpdev));
 1121 
 1122                 dumpdv = finddevice(buf);
 1123                 if (dumpdv == NULL) {
 1124                         /*
 1125                          * Device not configured.
 1126                          */
 1127                         goto nodumpdev;
 1128                 }
 1129         } else {                                /* (c) */
 1130                 if (DEV_USES_PARTITIONS(rootdv) == 0)
 1131                         goto nodumpdev;
 1132                 else {
 1133                         dumpdv = rootdv;
 1134                         dumpdev = MAKEDISKDEV(major(rootdev),
 1135                             device_unit(dumpdv), 1);
 1136                 }
 1137         }
 1138 
 1139         aprint_normal(" dumps on %s", dumpdv->dv_xname);
 1140         if (DEV_USES_PARTITIONS(dumpdv))
 1141                 aprint_normal("%c", DISKPART(dumpdev) + 'a');
 1142         aprint_normal("\n");
 1143         return;
 1144 
 1145  nodumpdev:
 1146         dumpdev = NODEV;
 1147         aprint_normal("\n");
 1148 }
 1149 
 1150 static struct device *
 1151 finddevice(const char *name)
 1152 {
 1153         struct device *dv;
 1154 #if defined(BOOT_FROM_MEMORY_HOOKS)
 1155         int j;
 1156 #endif /* BOOT_FROM_MEMORY_HOOKS */
 1157 
 1158 #ifdef BOOT_FROM_MEMORY_HOOKS
 1159         for (j = 0; j < NMD; j++) {
 1160                 if (strcmp(name, fakemdrootdev[j].dv_xname) == 0) {
 1161                         dv = &fakemdrootdev[j];
 1162                         return (dv);
 1163                 }
 1164         }
 1165 #endif /* BOOT_FROM_MEMORY_HOOKS */
 1166 
 1167         for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
 1168             dv = TAILQ_NEXT(dv, dv_list))
 1169                 if (strcmp(dv->dv_xname, name) == 0)
 1170                         break;
 1171         return (dv);
 1172 }
 1173 
 1174 static struct device *
 1175 getdisk(char *str, int len, int defpart, dev_t *devp, int isdump)
 1176 {
 1177         struct device   *dv;
 1178 #ifdef MEMORY_DISK_HOOKS
 1179         int             i;
 1180 #endif
 1181 
 1182         if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
 1183                 printf("use one of:");
 1184 #ifdef MEMORY_DISK_HOOKS
 1185                 if (isdump == 0)
 1186                         for (i = 0; i < NMD; i++)
 1187                                 printf(" %s[a-%c]", fakemdrootdev[i].dv_xname,
 1188                                     'a' + MAXPARTITIONS - 1);
 1189 #endif
 1190                 TAILQ_FOREACH(dv, &alldevs, dv_list) {
 1191                         if (DEV_USES_PARTITIONS(dv))
 1192                                 printf(" %s[a-%c]", dv->dv_xname,
 1193                                     'a' + MAXPARTITIONS - 1);
 1194                         else if (device_class(dv) == DV_DISK)
 1195                                 printf(" %s", dv->dv_xname);
 1196                         if (isdump == 0 && device_class(dv) == DV_IFNET)
 1197                                 printf(" %s", dv->dv_xname);
 1198                 }
 1199                 if (isdump)
 1200                         printf(" none");
 1201 #if defined(DDB)
 1202                 printf(" ddb");
 1203 #endif
 1204                 printf(" halt reboot\n");
 1205         }
 1206         return (dv);
 1207 }
 1208 
 1209 static struct device *
 1210 parsedisk(char *str, int len, int defpart, dev_t *devp)
 1211 {
 1212         struct device *dv;
 1213         char *cp, c;
 1214         int majdev, part;
 1215 #ifdef MEMORY_DISK_HOOKS
 1216         int i;
 1217 #endif
 1218         if (len == 0)
 1219                 return (NULL);
 1220 
 1221         if (len == 4 && strcmp(str, "halt") == 0)
 1222                 cpu_reboot(RB_HALT, NULL);
 1223         else if (len == 6 && strcmp(str, "reboot") == 0)
 1224                 cpu_reboot(0, NULL);
 1225 #if defined(DDB)
 1226         else if (len == 3 && strcmp(str, "ddb") == 0)
 1227                 console_debugger();
 1228 #endif
 1229 
 1230         cp = str + len - 1;
 1231         c = *cp;
 1232         if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
 1233                 part = c - 'a';
 1234                 *cp = '\0';
 1235         } else
 1236                 part = defpart;
 1237 
 1238 #ifdef MEMORY_DISK_HOOKS
 1239         for (i = 0; i < NMD; i++)
 1240                 if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) {
 1241                         dv = &fakemdrootdev[i];
 1242                         goto gotdisk;
 1243                 }
 1244 #endif
 1245 
 1246         dv = finddevice(str);
 1247         if (dv != NULL) {
 1248                 if (device_class(dv) == DV_DISK) {
 1249 #ifdef MEMORY_DISK_HOOKS
 1250  gotdisk:
 1251 #endif
 1252                         majdev = devsw_name2blk(dv->dv_xname, NULL, 0);
 1253                         if (majdev < 0)
 1254                                 panic("parsedisk");
 1255                         if (DEV_USES_PARTITIONS(dv))
 1256                                 *devp = MAKEDISKDEV(majdev, device_unit(dv),
 1257                                                     part);
 1258                         else
 1259                                 *devp = makedev(majdev, device_unit(dv));
 1260                 }
 1261 
 1262                 if (device_class(dv) == DV_IFNET)
 1263                         *devp = NODEV;
 1264         }
 1265 
 1266         *cp = c;
 1267         return (dv);
 1268 }
 1269 
 1270 /*
 1271  * snprintf() `bytes' into `buf', reformatting it so that the number,
 1272  * plus a possible `x' + suffix extension) fits into len bytes (including
 1273  * the terminating NUL).
 1274  * Returns the number of bytes stored in buf, or -1 if there was a problem.
 1275  * E.g, given a len of 9 and a suffix of `B':
 1276  *      bytes           result
 1277  *      -----           ------
 1278  *      99999           `99999 B'
 1279  *      100000          `97 kB'
 1280  *      66715648        `65152 kB'
 1281  *      252215296       `240 MB'
 1282  */
 1283 int
 1284 humanize_number(char *buf, size_t len, uint64_t bytes, const char *suffix,
 1285     int divisor)
 1286 {
 1287         /* prefixes are: (none), kilo, Mega, Giga, Tera, Peta, Exa */
 1288         const char *prefixes;
 1289         int             r;
 1290         uint64_t        umax;
 1291         size_t          i, suffixlen;
 1292 
 1293         if (buf == NULL || suffix == NULL)
 1294                 return (-1);
 1295         if (len > 0)
 1296                 buf[0] = '\0';
 1297         suffixlen = strlen(suffix);
 1298         /* check if enough room for `x y' + suffix + `\0' */
 1299         if (len < 4 + suffixlen)
 1300                 return (-1);
 1301 
 1302         if (divisor == 1024) {
 1303                 /*
 1304                  * binary multiplies
 1305                  * XXX IEC 60027-2 recommends Ki, Mi, Gi...
 1306                  */
 1307                 prefixes = " KMGTPE";
 1308         } else
 1309                 prefixes = " kMGTPE"; /* SI for decimal multiplies */
 1310 
 1311         umax = 1;
 1312         for (i = 0; i < len - suffixlen - 3; i++)
 1313                 umax *= 10;
 1314         for (i = 0; bytes >= umax && prefixes[i + 1]; i++)
 1315                 bytes /= divisor;
 1316 
 1317         r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes,
 1318             i == 0 ? "" : " ", prefixes[i], suffix);
 1319 
 1320         return (r);
 1321 }
 1322 
 1323 int
 1324 format_bytes(char *buf, size_t len, uint64_t bytes)
 1325 {
 1326         int     rv;
 1327         size_t  nlen;
 1328 
 1329         rv = humanize_number(buf, len, bytes, "B", 1024);
 1330         if (rv != -1) {
 1331                         /* nuke the trailing ` B' if it exists */
 1332                 nlen = strlen(buf) - 2;
 1333                 if (strcmp(&buf[nlen], " B") == 0)
 1334                         buf[nlen] = '\0';
 1335         }
 1336         return (rv);
 1337 }
 1338 
 1339 /*
 1340  * Return TRUE if system call tracing is enabled for the specified process.
 1341  */
 1342 boolean_t
 1343 trace_is_enabled(struct proc *p)
 1344 {
 1345 #ifdef SYSCALL_DEBUG
 1346         return (TRUE);
 1347 #endif
 1348 #ifdef KTRACE
 1349         if (ISSET(p->p_traceflag, (KTRFAC_SYSCALL | KTRFAC_SYSRET)))
 1350                 return (TRUE);
 1351 #endif
 1352 #ifdef SYSTRACE
 1353         if (ISSET(p->p_flag, P_SYSTRACE))
 1354                 return (TRUE);
 1355 #endif
 1356 #ifdef PTRACE
 1357         if (ISSET(p->p_flag, P_SYSCALL))
 1358                 return (TRUE);
 1359 #endif
 1360 
 1361         return (FALSE);
 1362 }
 1363 
 1364 /*
 1365  * Start trace of particular system call. If process is being traced,
 1366  * this routine is called by MD syscall dispatch code just before
 1367  * a system call is actually executed.
 1368  * MD caller guarantees the passed 'code' is within the supported
 1369  * system call number range for emulation the process runs under.
 1370  */
 1371 int
 1372 trace_enter(struct lwp *l, register_t code,
 1373     register_t realcode, const struct sysent *callp, void *args)
 1374 {
 1375         struct proc *p = l->l_proc;
 1376 
 1377 
 1378 #if defined(SYSCALL_DEBUG) || defined(KTRACE) || defined(PTRACE) || defined(SYSTRACE)
 1379 #ifdef SYSCALL_DEBUG
 1380         scdebug_call(l, code, args);
 1381 #endif /* SYSCALL_DEBUG */
 1382 
 1383 #ifdef KTRACE
 1384         if (KTRPOINT(p, KTR_SYSCALL))
 1385                 ktrsyscall(l, code, realcode, callp, args);
 1386 #endif /* KTRACE */
 1387 
 1388 #ifdef PTRACE
 1389         if ((p->p_flag & (P_SYSCALL|P_TRACED)) == (P_SYSCALL|P_TRACED))
 1390                 process_stoptrace(l);
 1391 #endif
 1392 
 1393 #ifdef SYSTRACE
 1394         if (ISSET(p->p_flag, P_SYSTRACE))
 1395                 return systrace_enter(l, code, args);
 1396 #endif
 1397 #endif /* SYSCALL_DEBUG || {K,P,SYS}TRACE */
 1398         return 0;
 1399 }
 1400 
 1401 /*
 1402  * End trace of particular system call. If process is being traced,
 1403  * this routine is called by MD syscall dispatch code just after
 1404  * a system call finishes.
 1405  * MD caller guarantees the passed 'code' is within the supported
 1406  * system call number range for emulation the process runs under.
 1407  */
 1408 void
 1409 trace_exit(struct lwp *l, register_t code, void *args, register_t rval[],
 1410     int error)
 1411 {
 1412         struct proc *p = l->l_proc;
 1413 
 1414 #if defined(SYSCALL_DEBUG) || defined(KTRACE) || defined(PTRACE) || defined(SYSTRACE)
 1415 #ifdef SYSCALL_DEBUG
 1416         scdebug_ret(l, code, error, rval);
 1417 #endif /* SYSCALL_DEBUG */
 1418 
 1419 #ifdef KTRACE
 1420         if (KTRPOINT(p, KTR_SYSRET)) {
 1421                 KERNEL_PROC_LOCK(l);
 1422                 ktrsysret(l, code, error, rval);
 1423                 KERNEL_PROC_UNLOCK(l);
 1424         }
 1425 #endif /* KTRACE */
 1426         
 1427 #ifdef PTRACE
 1428         if ((p->p_flag & (P_SYSCALL|P_TRACED)) == (P_SYSCALL|P_TRACED))
 1429                 process_stoptrace(l);
 1430 #endif
 1431 
 1432 #ifdef SYSTRACE
 1433         if (ISSET(p->p_flag, P_SYSTRACE)) {
 1434                 KERNEL_PROC_LOCK(l);
 1435                 systrace_exit(l, code, args, rval, error);
 1436                 KERNEL_PROC_UNLOCK(l);
 1437         }
 1438 #endif
 1439 #endif /* SYSCALL_DEBUG || {K,P,SYS}TRACE */
 1440 }

Cache object: 6baa8f5d76b68fa7e8eaea216883b574


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.