tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

MAKEDEV, pax, and mtree



MAKEDEV(8) internally tries to use pax(8) to create device nodes.
However, this doesn't work well if the device nodes already exist; at
best, pax will complain "file would overwrite itself", and at worst, pax
will not correct a file whose type or permissions are incorrect.

Here's a patch to let MAKEDEV use mtree in preference to pax.  In
normal use, it's expected that mtree will be available and will work.
When MAKEDEV is invoked from init(8) to populate a previously empty
/dev, it's expected that mtree will not be available, but pax will be
available, and the problem that pax has with already existing device
nodes will not be an issue.

I don't know what do do with the MAKEDEV "-f" flag.  If MAKEDEV invokes
mknod(8), then MAKEDEV's "-f" flag selects between mknod's "-r" and
"-R" flags.  If MAKEDEV invokes pax(1), I don't think the "-f" flag
makes sense at all.  If MAKEDEV invokes mtree(8), would it make sense
for MAKEDEV's "-f" flag to select between "mtree -e -U -W" and "mtree -e
-U"?

--apb (Alan Barrett)

Index: src/etc/MAKEDEV.tmpl
===================================================================
--- MAKEDEV.tmpl        5 Mar 2008 02:29:51 -0000       1.102
+++ MAKEDEV.tmpl        7 Apr 2008 20:17:07 -0000
@@ -1,7 +1,7 @@
 #!/bin/sh -
 #      $NetBSD: MAKEDEV.tmpl,v 1.102 2008/03/05 02:29:51 christos Exp $
 #
-# Copyright (c) 2003,2007 The NetBSD Foundation, Inc.
+# Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -304,13 +304,14 @@
 usage()
 {
        cat 1>&2 << _USAGE_
-Usage: ${0##*/} [-fMs] [-m mknod] [-p pax] special [...]
+Usage: ${0##*/} [-fMs] [-m mknod] [-p pax] [-t mtree] special [...]
        Create listed special devices.  Options:
        -f              Force permissions to be updated on existing devices.
        -M              Create memory file system.
        -m mknod        Name of mknod(8) program.  [\$TOOL_MKNOD or mknod]
        -p pax          Name of pax(2) program.  [\$TOOL_PAX or pax]
        -s              Generate mtree(8) specfile instead of creating devices.
+       -t mtree        Name of mtree(8) program.  [\$TOOL_MTREE or mtree]
 
 _USAGE_
        exit 1
@@ -376,8 +377,8 @@
 }
 
 # check_pax path_to_pax
-#      Check whether pax supports the command line options we
-#      will want to use.
+#      Check whether pax exists and supports the command line options
+#      and input format that we will want to use.
 #
 check_pax()
 {
@@ -385,6 +386,16 @@
        echo ". type=dir optional" | nooutput -12 "${pax}" -r -w -M -pe .
 }
 
+# check_mtree path_to_mtree
+#      Check whether mtree exists and supports the command line options
+#      and input format that we will want to use.
+#
+check_mtree()
+{
+       local mtree="$1"
+       echo ". type=dir optional" | nooutput -12 "${mtree}" -e -U
+}
+
 # setup args...
 #      Parse command line arguments, exit on error.
 #      Callers should shift $((OPTIND - 1)) afterwards.
@@ -393,14 +404,18 @@
 {
        PATH=/sbin:/usr/sbin:/bin:/usr/bin:/rescue
 
+       : ${TOOL_MKNOD:=mknod}
+       : ${TOOL_MTREE:=mtree}
+       : ${TOOL_PAX:=pax}
        do_create_mfs=false
        do_force=false
        do_mknod=false
        do_pax=false
+       do_mtree=false
        do_redirect=false
        do_specfile=false
-       opts=
-       while getopts Mfm:p:s ch; do
+       opts= # options passed to MAKEDEV.local child process
+       while getopts Mfm:p:st: ch; do
                # Options that should not be passed through to
                # MAKEDEV.local are not added to $opts.
                case ${ch} in
@@ -431,6 +446,17 @@
                s)      do_specfile=true
                        opts="${opts} -s"
                        ;;
+               t)      TOOL_MTREE="${OPTARG}"
+                       if check_mtree "${TOOL_MTREE}"; then
+                               do_mtree=true
+                               # do not add this to $opts; we will later
+                               # add "-s" instead.
+                       else
+                               warn "Ignored -t option:" \
+                                       "${TOOL_MTREE} is missing or broken"
+                               do_mknod=true
+                       fi
+                       ;;
                *)      usage ;;
                esac
        done
@@ -463,32 +489,42 @@
 
        # do_force requires mknod
        if $do_force; then
-               if $do_pax || $do_specfile; then
+               if $do_mtree || $do_pax || $do_specfile; then
                        warn "-f option works only with mknod"
                        exit 1
                fi
                do_mknod=true
        fi
 
-       # If no other options take precedence, then default to
-       # using pax, if it appears to work.
-       if ! $do_mknod && ! $do_specfile && ! $do_pax; then
-               : ${TOOL_PAX:=pax}
-               if check_pax "${TOOL_PAX}"; then
+       # If no explicit method was specified on the command line
+       # or forced above, then use one of mtree, pax, or mknod,
+       # in that order of preference.
+       #
+       # mtree is preferred over pax, because pax complains about "file
+       # would overwrite itself" when trying to update a file that
+       # already exists.  However, mtree is less likely than pax to be
+       # available early in the boot sequence, when init(8) may invoke
+       # MAKEDEV(8).  mknod is just very slow, because the shell has to fork
+       # for each device node.
+       if ! ( $do_mtree || $do_pax || $do_mknod || $do_specfile ); then
+               if check_mtree "${TOOL_MTREE}"; then
+                       do_mtree=true
+               elif check_pax "${TOOL_PAX}"; then
                        do_pax=true
                else
                        do_mknod=true
                fi
        fi
 
-       # Now we need exactly one of do_pax, do_mknod, or do_specfile.
-       case $(( $($do_pax && echo 1 || echo 0) + \
+       # Now we need exactly one node-creation method.
+       case $(( $($do_mtree && echo 1 || echo 0) + \
+               $($do_pax && echo 1 || echo 0) + \
                $($do_mknod && echo 1 || echo 0) + \
                $($do_specfile && echo 1 || echo 0) ))
        in
-       1)      : OK ;;
-       *)      
-               warn "-m, -p, and -s options are mutually exclusive"
+       1)      : OK
+               ;;
+       *)      warn "-m, -p, -s, and -t options are mutually exclusive"
                exit 1
                ;;
        esac
@@ -496,16 +532,16 @@
        # If we are using mknod, then decide what options to pass it.
        if $do_mknod; then
                MKNOD="${TOOL_MKNOD:-mknod} -F netbsd"
-               if $do_force; then
+       if $do_force; then
                        MKNOD="${MKNOD} -R"
-               else
+       else
                        MKNOD="${MKNOD} -r"
                fi
        fi
 
-       # do_pax internally implies do_specfile.  This happens after
-       # checking for mutually-exclusive options.
-       if $do_pax && ! $do_specfile; then
+       # do_mtree or do_pax internally implies do_specfile.
+       # This happens after checking for mutually-exclusive options.
+       if ($do_mtree || $do_pax) && ! $do_specfile; then
                do_specfile=true
                opts="${opts} -s"
        fi
@@ -518,7 +554,8 @@
 wrap_makedev()
 {
        if $do_specfile; then
-               # "optional" tells pax(1) not to create the directory itself.
+               # "." must appear as the first line of the specfile.
+               # "optional" means do not create the directory itself.
                echo ". type=dir optional"
        fi
        "$@"
@@ -547,9 +584,12 @@
                unset count_nodes
        fi
 
-       if $do_pax ; then
-               # wrap_makedev will print an mtree specification because
-               # do_pax implies do_specfile.  pax will create device nodes.
+       # If using mtree or pax, then wrap_makedev should print an mtree
+       # specification, which we postprocess to create the device nodes.
+       # Otherwise, wrap_makedev should do all the work itself.
+       if $do_mtree ; then
+               wrap_makedev $makedev ${1+"$@"} | ${TOOL_MTREE} -e -U
+       elif $do_pax ; then
                wrap_makedev $makedev ${1+"$@"} | ${TOOL_PAX} -r -w -M -pe .
        else
                wrap_makedev $makedev ${1+"$@"}
@@ -606,7 +646,7 @@
                return
        fi
        if $do_specfile; then
-               echo "./$1 type=dir mode=$2 gid=$g_wheel uid=$u_root optional"
+               echo "./$1 type=dir mode=$2 gid=$g_wheel uid=$u_root"
        else
                nooutput -2 mkdir $1
                chmod $2 $1


Home | Main Index | Thread Index | Old Index