summaryrefslogtreecommitdiff
path: root/sutils
diff options
context:
space:
mode:
Diffstat (limited to 'sutils')
-rw-r--r--sutils/ChangeLog375
-rw-r--r--sutils/MAKEDEV.sh181
-rw-r--r--sutils/Makefile44
-rw-r--r--sutils/clookup.c168
-rwxr-xr-xsutils/e2os.sh153
-rw-r--r--sutils/fsck.c568
-rw-r--r--sutils/fstab.c956
-rw-r--r--sutils/fstab.h178
-rw-r--r--sutils/halt.c39
-rw-r--r--sutils/losetup.sh66
-rw-r--r--sutils/reboot.c39
-rw-r--r--sutils/swapoff.c2
-rw-r--r--sutils/swapon.c165
-rw-r--r--sutils/update.c54
14 files changed, 2988 insertions, 0 deletions
diff --git a/sutils/ChangeLog b/sutils/ChangeLog
new file mode 100644
index 00000000..11c34ba9
--- /dev/null
+++ b/sutils/ChangeLog
@@ -0,0 +1,375 @@
+1999-12-03 Roland McGrath <roland@baalperazim.frob.com>
+
+ * MAKEDEV.sh (mkdev: full): New device, using /hurd/null --full.
+ (mkdev: std): Add full to the standard list.
+
+1999-11-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * MAKEDEV.sh (mkdev: time): Use --no-cache flag.
+ (mkdev: mem): New storeio device.
+ (mkdev: std): Add mem to standard list.
+
+ * Makefile (progs, scripts): New variables.
+ (targets, special-targets, SRCS, OBJS): Define in terms of those.
+ (libshouldbeinlibc dep rule): Replaced with static pattern rule
+ with $(progs) as target list, giving %.o dep as well.
+
+1999-11-16 Roland McGrath <roland@baalperazim.frob.com>
+
+ * swapon.c (swaponoff): Check for a null default pager port.
+
+1999-10-01 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fstab.c (fstypes_get): Check strdup return for ENOMEM failure.
+ (fstypes_find_program): New function, #if 0'd out for now.
+ (fstab_argp, fstab_argp_create, options, parse_opt): New variables
+ and functions.
+ * fstab.h: Misc comment fixes.
+ (struct fstab_argp_params): New type.
+ (fstab_argp, fstab_argp_create): Declare them.
+ * fsck.c (options): Remove --fstab/-F, --search-fmts/-S,
+ --exclude-root/-R, --exclude/-X, --fstype/-t, --all/-A;
+ all of these are now factored out into fstab_argp.
+ (main): Remove parsing code for options now in fstab_argp.
+ Instead, use fstab_argp as an argp_child and use fstab_argp_create
+ to process the option-parsing results into a struct fstab * to process.
+
+ * fstab.c (fstab_read): Undo change of 1999-09-17.
+ It should not be necessary at all, given 1999-05-23 change, and:
+ (fstab_find_mount): Do not consider name "ignore" to match any mount.
+
+1999-10-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * MAKEDEV.sh (fd): Pass --directory to /hurd/magic translator.
+
+1999-09-17 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * fstab.c (fstab_read): Ignore filesystems with types of ignore,
+ nfs, or swap.
+
+1999-09-14 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * MAKEDEV.sh (mkdev): pty master and slave nodes should have mode
+ 666, not 640. Reported by Marcus Brinkmann
+ <Marcus.Brinkmann@ruhr-uni-bochum.de>.
+
+1999-07-10 Roland McGrath <roland@baalperazim.frob.com>
+
+ * clookup.c: Add #include <sys/mman.h>.
+
+ * Makefile (special-targets): Add losetup.
+ (SCRIPTS): Add losetup.sh.
+ * losetup.sh: New file.
+
+1999-07-03 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * clookup.c (file_name_lookup_carefully): Use munmap instead of
+ vm_deallocate.
+
+1999-06-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fstab.c (fstypes_get): Don't free PROGRAM twice on ENOENT failure.
+
+ * fsck.c (options): Add -t/--fstype option.
+ (main): Parse that option, and use it to constrain fstab list.
+
+ * fsck.c (FSCK_F_DRYRUN): New macro.
+ (options, main): Add -N/--dry-run option to set it.
+ (fs_start_fsck): If FSCK_F_DRYRUN set, just print out and return zero.
+ * fsck.c (fscks_start_fsck): If FSCK_F_DRYRUN is set, don't try to
+ make read-only, just print a message that we would.
+
+ * fsck.c (options, main): Change --fstab from -t to -F.
+
+1999-06-10 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fsck.c (options): Add -A/--all and -R/--exclude-root options for
+ compatibility with Linux, and --exclude=PATTERN as general form.
+ (main): Parse them. Constrain fstab list by exclude patterns.
+
+ * fsck.c (fsck): Don't check for "noauto" mntopt. No other system
+ skips a filesystem because of it.
+ (fsck): Always start at pass 1, not 0. In every other system,
+ "pass 0" always means to skip that filesystem entirely.
+
+1999-05-23 Roland McGrath <roland@baalperazim.frob.com>
+
+ * MAKEDEV.sh (ECHO, EXEC): Do not export.
+ (DEVDIR): Initialize to `pwd` before argument parsing.
+ (_CWD): Don't set this.
+ (lose): New function. Use it for all miscellaneous fatal errors.
+ (mkdev): Disallow directory names. Always use ${DEVDIR} for name to
+ embed in translator settings.
+ Rewrite syntax checking for disk device names.
+
+ * fstab.c, fstab.h: Add numerous `const' qualifiers.
+
+ * fstab.c (fstab_find_mount): Don't count "none" or "-" as matching
+ any other entry.
+
+ * fsck.c (struct fsck): Don't use bitfield.
+
+1999-05-15 Roland McGrath <roland@baalperazim.frob.com>
+
+ * swapon.c: Support -a (reading fstab).
+
+1999-05-13 Roland McGrath <roland@baalperazim.frob.com>
+
+ * MAKEDEV.sh (case 'time'): Make /dev/time mode 644, not 666.
+
+Thu Feb 18 02:13:47 1999 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * MAKEDEV.sh (mkdev): put `time' in single-quotes; it's a reserved
+ word in bash 2.02 and this protects it. Reported by OKUJI
+ Yoshinori <okuji@kuicr.kyoto-u.ac.jp>.
+
+Mon Feb 1 16:27:15 1999 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * MAKEDEV.sh (PATH): Add /usr/bin out of deference to users
+ lacking the /usr symlink. Requested by Marcus Brinkmann
+ <Marcus.Brinkmann@ruhr-uni-bochum.de>.
+
+1998-11-29 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fsck.c (main): Add braces to silence gcc warning.
+
+ * fstab.c: Rename fsys_remount -> fsys_update in extern decl.
+
+1998-11-28 Roland McGrath <roland@baalperazim.frob.com>
+
+ * clookup.c (file_name_lookup_carefully): Change __getuids to geteuids.
+ Use hurd_file_name_lookup instead of __hurd_file_name_lookup.
+
+1998-10-24 Roland McGrath <roland@baalperazim.frob.com>
+
+ * clookup.c (file_name_lookup_carefully): Use getdport instead of
+ __getdport, getumask () instead of _hurd_umask.
+
+1998-10-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fstab.c (fstab_add_mntent): Add braces to silence gcc warning.
+ (fs_readonly): Likewise.
+
+1998-07-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * swapon.c (main): Fix return type to int, and use return.
+
+1997-10-28 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh (mkdev): Support 256 ptys.
+
+1997-08-20 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fstab.c (_fs_check_mounted): file_get_translator_cntl can also
+ return ENXIO for an inactive translator.
+
+1997-08-19 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh (mkdev): Handle devices of the form "cd*".
+
+1997-07-22 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh (time): Use /hurd/storeio instead of /hurd/devport.
+
+1997-07-09 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * Makefile (targets): Add swapon & swapoff.
+ (SRCS): Add swapon.c & swapoff.c.
+ Add dependencies on libstore.
+ (HURDLIBS): Add libstore.
+
+1997-06-25 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh (mkdev): Add missing `ln' to command for stderr.
+
+1997-06-24 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh: Use bash fancy variables instead of various programs.
+ Try to get the correct devdir even if it's not the cwd.
+ Add new options --verbose/-v and --dry-run/-n.
+ (cmd): New function.
+ (st, mkdir): Use cmd to execute any real commands.
+
+1997-06-23 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh: Add the --devdir/-D option.
+ Use the basename of $I instead of $I for various things.
+ Correctly put derived names in the same directory as the arg.
+
+1997-06-21 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * e2os.sh: Use conv=notrunc when writing the superblock back to
+ the filesystem device, in case it's a file and not a real device.
+
+ * e2os.sh: If $OD & $AWK don't exist, try to get them from
+ /usr/bin, so that this script works under linux too.
+
+Fri Feb 28 21:27:20 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (fsck_cleanup): Correctly remove from fscks chain.
+
+Sun Feb 23 02:57:46 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh (mkdev): Make I local.
+
+Wed Feb 19 23:08:04 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * halt.c, reboot.c, fsck.c (argp_program_version): Make const.
+
+Wed Feb 5 11:50:19 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fstab.c (fstypes_get): Improve error behavior a bit.
+
+ * fsck.c (fsck): In non-automatic mode, print a warning if a
+ filesystem is of a type that can't be fscked.
+
+Tue Feb 4 17:09:39 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fstab.c (fs_set_mntent): Avoid null deferences.
+ (fstypes_get): Fill in FSTYPE in the case where we added a new type.
+
+Thu Sep 26 15:36:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * Makefile (targets, special-targets): Add MAKEDEV.
+ (SCRIPTS): Add MAKEDEV.sh.
+ (DIST_FILES): Variable removed.
+ (all): Target removed.
+ ($(prefix)/dev/MAKEDEV): Get rid of dependencies.
+ Implement with a symbolic link to /sbin/MAKEDEV.
+ (%: %.sh): Variable removed.
+
+Tue Sep 24 14:46:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh: Fix argument parsing.
+ (zero): Use `storeio -Tzero' instead of `null -z'.
+
+Thu Sep 19 17:48:59 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fstab.c (fs_remount): Use fsys_update instead of fsys_remount.
+
+Wed Sep 18 19:12:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh: Use a shell function `mkdev' for recursion, rather
+ than calling this script recursively.
+
+Thu Sep 12 18:53:42 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (fs_start_fsck): Print an error for filesystem types we
+ don't know how to fsck, instead of dying with an assertion failure.
+
+Thu Sep 19 16:58:18 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * Makefile (install): Depend on installation directory directly;
+ don't make installed files depend on it.
+
+Tue Sep 17 12:36:09 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * Makefile ($(prefix)/dev/MAKEDEV): Depend on $(prefix)/dev.
+ ($(prefix)/dev): New target.
+
+Thu Sep 12 16:38:11 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * Makefile (HURDLIBS): New variable.
+
+Sun Sep 8 13:57:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * MAKEDEV.sh: New file.
+ * Makefile (DIST_FILES): New variable.
+ (install): Depend on $(prefix)/dev/MAKEDEV.
+ (all): Depend on MAKEDEV.
+ ($(prefix)/dev/MAKEDEV): New rule.
+
+Thu Sep 5 11:40:00 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * Makefile: Use $(top_srcdir)/sh-version.sed to make executables
+ from .sh files.
+
+ * fsck.c: Include <version.h>.
+ (argp_program_version): Define with STANDARD_HURD_VERSION.
+ * halt.c: Likewise.
+ * reboot.c: Likewise.
+
+Tue Aug 27 12:06:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * reboot.c, halt.c (main): Add argument parsing.
+ (argp_program_version): New variable.
+ <argp.h>, <hurd.h>: New includes.
+ * Makefile (fsck): Remove dependency on libshouldbeinlibc.a.
+ (reboot halt fsck): Add dependency on libshouldbeinlibc.a.
+
+Mon Aug 19 15:17:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (doc): Supply a useful value.
+
+Wed Aug 14 13:32:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * e2os.sh: Add `;' before last commands inside { } pairs.
+ (OS_FREEBSD, OS_LITES): New variables.
+ Add symbolic names for freebsd & lites.
+
+Mon Aug 12 10:51:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * e2os.sh: New file.
+ * Makefile (targets): Add e2os.
+ (SRCS): Add $(SCRIPTS).
+ (special-targets, SCRIPTS, LCLHDRS): New variables.
+
+Thu Aug 1 16:29:31 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * clookup.c (file_name_lookup_carefully/lookup): When appending
+ TAIL to RETRY_NAME, use strcpy instead of strcat.
+
+Sat Jul 6 19:55:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c: (argp_program_version): New variable.
+
+Wed Jul 3 14:22:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fstab.c (fstab_add_fs): Don't SEGV if COPY is 0.
+
+Thu Jun 27 00:01:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (fsck): Fsck pass 0 if not in automatic mode. Respect
+ `noauto' option in automatic mode.
+ (main): Set FSCK_F_AUTO flag if in automatic mode.
+ (FSCK_F_AUTO): New macro.
+ (fs_start_fsck): When deciding to use a flags arg, mask flags
+ against an explicit list of valid ones.
+
+Tue Jun 25 18:39:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (main, options): Add --writable/-w option.
+ (FSCK_F_WRITABLE): New macro.
+ (struct fsck): Rename WAS_READONLY field to MAKE_WRITABLE.
+ (fscks_start_fsck): Change to set make_writable field instead of
+ was_readonly.
+ (fsck_cleanup): Change RESTORE_WRITABLE to MAKE_WRITABLE.
+ (fscks_wait): Likewise.
+
+Thu Jun 20 14:08:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (fsck): Wait for fscks to finish.
+ * fstab.c (fstypes_create): Copy SEARCH_FMTS contents into NEW.
+ (fs_set_mntent): Don't keep old fsys fields if the mnt_dir is changed.
+ (fstab_add_mntent): Initialize fields in FS with non-zero values.
+ (_fs_check_mounted): The root is always mounted.
+
+Wed Jun 19 10:44:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fstab.c (fs_set_readonly, fs_remount): If fsys_set_options
+ returns EINVAL, return EOPNOTSUPP instead.
+ (fs_set_readonly): Use fsys_set_readonly.
+ (fs_remount): Use fsys_remount.
+ (fs_readonly): Use fsys_get_readonly.
+ (_fs_check_mounted): Use file_name_lookup_carefully.
+ * clookup.c: New file.
+ * fsck.c (_debug): New variable.
+ (debug, fs_debug): New macros.
+ (fs_start_fsck, fscks_start_fsck, fsck_cleanup, fscks_wait, fsck, main):
+ Add debugging noise.
+ (main): Use FSTAB_PATH instead of _PATH_MNTTAB.
+ (args_doc): Fix.
+
+Tue Jun 18 22:56:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsck.c (options): Rename `--max-parallel' to `--parallel'.
diff --git a/sutils/MAKEDEV.sh b/sutils/MAKEDEV.sh
new file mode 100644
index 00000000..511deed2
--- /dev/null
+++ b/sutils/MAKEDEV.sh
@@ -0,0 +1,181 @@
+#!/bin/sh
+#
+# Make standard devices
+#
+
+PATH=/bin:/usr/bin
+
+ECHO=: # Change to "echo" to echo commands.
+EXEC="" # Change to ":" to suppress command execution.
+DEVDIR=`pwd` # Reset below by -D/--devdir command line option.
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "\
+Usage: $0 [OPTION...] DEVNAME...
+Make filesystem nodes for accessing standard system devices
+
+ -D, --devdir=DIR Use DIR when a device node name must be
+ embedded in a translator; default is the cwd
+ -n, --dry-run Don't actually execute any commands
+ -v, --verbose Show what commands are executed to make the devices
+ -?, --help Give this help list
+ --usage Give a short usage message
+ -V, --version Print program version"
+ exit 0;;
+ --devdir) DEVDIR="$2"; shift 2;;
+ --devdir=*) DEVDIR="`echo "$1" | sed 's/^--devdir=//'`"; shift 1;;
+ -D) DEVDIR="$2"; shift 2;;
+ -D*) DEVDIR="`echo "$1" | sed 's/^-D//'`"; shift 1;;
+ --verbose|-v) ECHO=echo; shift;;
+ --dry-run|-n) EXEC=:; shift;;
+ -nv|-vn) ECHO=echo; EXEC=:; shift;;
+ --usage)
+ echo "Usage: $0 [-V?] [-D DIR] [--help] [--usage] [--version] [--devdir=DIR] DEVNAME..."
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_MAKEDEV_"; exit 0;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+case "$#" in 0)
+ echo 1>&2 "Usage: $0 [OPTION...] DEVNAME..."
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information"
+ exit 1;;
+esac
+
+function cmd {
+ eval $ECHO "$@"
+ eval $EXEC "$@"
+}
+
+function st {
+ local NODE="$1"
+ local OWNER="$2"
+ local PERM="$3"
+ shift 3
+ if cmd settrans -cg "$NODE"; then
+ cmd chown "$OWNER" "$NODE"
+ cmd chmod "$PERM" "$NODE"
+ cmd settrans "$NODE" "$@"
+ fi
+}
+
+function lose {
+ local line
+ for line; do
+ echo 1>&2 "$0: $line"
+ done
+ exit 1
+}
+
+function mkdev {
+ local I
+ for I; do
+ case "$I" in
+ /* | */*)
+ lose "Device names cannot contain directories" \
+ "Change to target directory and run $0 from there."
+ ;;
+
+ std)
+ mkdev console tty null zero full fd time mem
+ ;;
+ console|tty[0-9][0-9a-f]|tty[0-9a-f]|com[0-9])
+ st $I root 600 /hurd/term ${DEVDIR}/$I device $I;;
+ null)
+ st $I root 666 /hurd/null;;
+ full)
+ st $I root 666 /hurd/null --full;;
+ zero)
+ st $I root 666 /hurd/storeio -Tzero;;
+ tty)
+ st $I root 666 /hurd/magic tty;;
+ fd)
+ st $I root 666 /hurd/magic --directory fd
+ cmd ln -f -s fd/0 stdin
+ cmd ln -f -s fd/1 stdout
+ cmd ln -f -s fd/2 stderr
+ ;;
+ 'time')
+ st $I root 644 /hurd/storeio --no-cache time ;;
+ mem)
+ st $I root 660 /hurd/storeio --no-cache mem ;;
+
+ # ptys
+ [pt]ty[pqrstuvwxyzPQRST]?)
+ # Make one pty, both the master and slave halves.
+ local id="${I:3}"
+ st pty$id root 666 /hurd/term ${DEVDIR}/pty$id \
+ pty-master ${DEVDIR}/tty$id
+ st tty$id root 666 /hurd/term ${DEVDIR}/tty$id \
+ pty-slave ${DEVDIR}/pty$id
+ ;;
+ [pt]ty[pqrstuvwxyzPQRST])
+ # Make a bunch of ptys.
+ mkdev ${I}0 ${I}1 ${I}2 ${I}3 ${I}4 ${I}5 ${I}6 ${I}7
+ mkdev ${I}8 ${I}9 ${I}a ${I}b ${I}c ${I}d ${I}e ${I}f
+ ;;
+
+ fd*|mt*)
+ st $I root 640 /hurd/storeio $I
+ ;;
+
+ [hrsc]d*)
+ local n="${I#?d}"
+ local major="${n%%[!0-9]*}"
+ if [ -z "$major" ]; then
+ lose "$I: Invalid device name: must supply a device number"
+ fi
+ local minor="${n##$major}"
+ case "$minor" in
+ '') ;; # Whole disk
+ [a-z]) ;; # BSD partition syntax, no slice syntax
+ s[1-9]*) # Slice syntax.
+ local slicestuff="${minor#s}"
+ local slice="${slicestuff%%[!0-9]*}"
+ local rest="${slicestuff##$slice}"
+ case "$slice" in
+ [1-9] | [1-9][0-9]) ;;
+ *)
+ lose "$I: Invalid slice number \`$slice'"
+ ;;
+ esac
+ case "$rest" in
+ '') ;; # Whole slice
+ [a-z]) ;; # BSD partition after slice
+ *)
+ lose "$I: Invalid partition \`$rest'"
+ ;;
+ esac
+ ;;
+ *)
+ lose "$I: Invalid slice or partition syntax"
+ ;;
+ esac
+
+ # The device name passed all syntax checks, so finally use it!
+ st $I root 640 /hurd/storeio $I
+ ;;
+
+ # Linux compatibility
+ loop*)
+ # In Linux an inactive "/dev/loopN" device acts like /dev/null.
+ # The `losetup' script changes the translator to "activate" the device.
+ st $I root 640 /hurd/null
+ ;;
+ *)
+ lose "$I: Unknown device name"
+ ;;
+ esac
+ done
+}
+
+mkdev "$@"
diff --git a/sutils/Makefile b/sutils/Makefile
new file mode 100644
index 00000000..5b5c2110
--- /dev/null
+++ b/sutils/Makefile
@@ -0,0 +1,44 @@
+# Makefile for sutils
+#
+# Copyright (C) 1996,97,99 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+dir := sutils
+makemode := utilities
+
+progs = reboot halt fsck swapon swapoff
+scripts = e2os MAKEDEV losetup
+targets = $(special-targets) $(progs)
+special-targets = $(scripts)
+installationdir = $(sbindir)
+SRCS = $(progs:=.c) $(scripts:=.sh)
+LCLHDRS = fstab.h
+
+OBJS = $(progs:=.c)
+HURDLIBS = store shouldbeinlibc
+
+include ../Makeconf
+
+fsck: fstab.o clookup.o
+swapon swapoff: ../libstore/libstore.a
+$(progs): %: %.o ../libshouldbeinlibc/libshouldbeinlibc.a
+
+install: $(prefix)/dev $(prefix)/dev/MAKEDEV
+$(prefix)/dev/MAKEDEV:
+ ln -s ../sbin/MAKEDEV $@
+$(prefix)/dev:
+ @$(MKINSTALLDIRS) $@
diff --git a/sutils/clookup.c b/sutils/clookup.c
new file mode 100644
index 00000000..d0f69d9b
--- /dev/null
+++ b/sutils/clookup.c
@@ -0,0 +1,168 @@
+/* Careful filename lookup
+
+ Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/id.h>
+#include <hurd/fsys.h>
+
+
+/* This function is like file_name_lookup, but tries hard to avoid starting
+ any passive translators. If a node with an unstarted passive translator
+ is encountered, ENXIO is returned in ERRNO; other errors are as for
+ file_name_lookup. Note that checking for an active translator currently
+ requires fetching the control port, which is a priveleged operation. */
+file_t
+file_name_lookup_carefully (const char *name, int flags, mode_t mode)
+{
+ error_t err;
+ file_t node;
+ uid_t *uids; /* Authentication of the current process. */
+ gid_t *gids;
+ size_t num_uids, num_gids;
+
+ /* Do the actual directory lookup. We only do the first pathname element
+ of NAME, appending the rest to any RETRY_NAME returned. We then make
+ sure the result node doesn't have a passive translator with no active
+ translator started (but we make an exception for symlinks) -- if it
+ does, we just return ENXIO. */
+ error_t lookup (file_t dir, char *name, int flags, mode_t mode,
+ retry_type *retry, string_t retry_name,
+ mach_port_t *node)
+ {
+ error_t err;
+ char *head, *tail;
+ char *slash = index (name, '/');
+
+ if (slash)
+ {
+ *stpncpy (head = alloca (slash - name + 1), name, slash - name) = 0;
+ tail = slash + 1;
+ }
+ else
+ {
+ head = name;
+ tail = 0;
+ }
+
+ err = dir_lookup (dir, head, flags | O_NOTRANS, mode,
+ retry, retry_name, node);
+ if (err)
+ return err;
+
+ if (*node != MACH_PORT_NULL
+ && (!(flags & O_NOTRANS) || tail || *retry_name))
+ /* The dir_lookup has returned a node to use for the next stage of
+ the lookup. Unless it's the last element of the path and FLAGS
+ has O_NOTRANS set (in which case we just return what we got as
+ is), we have to simulate the above lookup being done without
+ O_NOTRANS. Do this being careful not to start any translators. */
+ {
+ char _ptrans[1024], *ptrans = _ptrans;
+ size_t ptrans_len = sizeof _ptrans;
+
+ err = file_get_translator (*node, &ptrans, &ptrans_len);
+ if (! err)
+ /* Has a passive translator, see if there's an active one too. */
+ {
+ fsys_t fsys; /* Active translator control port. */
+
+ if (ptrans != _ptrans)
+ /* Deallocate out-of-line memory from file_get_translator. */
+ munmap (ptrans, ptrans_len);
+
+ err = file_get_translator_cntl (*node, &fsys);
+ if (! err)
+ /* There is! Get its root node to use as the actual file. */
+ {
+ file_t unauth_dir; /* DIR unauthenticated. */
+ err = io_restrict_auth (dir, &unauth_dir, 0, 0, 0, 0);
+ if (! err)
+ {
+ file_t old_node = *node;
+ err = fsys_getroot (fsys,
+ unauth_dir, MACH_MSG_TYPE_MOVE_SEND,
+ uids, num_uids, gids, num_gids,
+ flags & ~O_NOTRANS, retry,
+ retry_name, node);
+ if (! err)
+ mach_port_deallocate (mach_task_self (), old_node);
+ }
+ mach_port_deallocate (mach_task_self (), fsys);
+ }
+ }
+ else if (err == EINVAL)
+ /* No passive translator. */
+ err = 0;
+
+ if (!err && tail)
+ /* Append TAIL to RETRY_NAME. */
+ {
+ size_t rtn_len = strlen (retry_name);
+ if (rtn_len + 1 + strlen (tail) + 1 > sizeof (string_t))
+ err = ENAMETOOLONG; /* Argh. Lovely string_t. */
+ else
+ {
+ if (rtn_len > 0 && retry_name[rtn_len - 1] != '/')
+ retry_name[rtn_len++] = '/';
+ strcpy (retry_name + rtn_len, tail);
+ }
+ }
+
+ if (err)
+ mach_port_deallocate (mach_task_self (), *node);
+ }
+
+ return err;
+ }
+
+ /* Fetch uids for use with fsys_getroot. */
+ num_uids = geteuids (0, 0);
+ if (num_uids < 0)
+ return errno;
+ uids = alloca (num_uids * sizeof (uid_t));
+ num_uids = geteuids (num_uids, uids);
+ if (num_uids < 0)
+ return errno;
+
+ /* ... and gids. */
+ num_gids = getgroups (0, 0);
+ if (num_gids < 0)
+ return errno;
+ gids = alloca (num_gids * sizeof (gid_t));
+ num_gids = getgroups (num_gids, gids);
+ if (num_gids < 0)
+ return errno;
+
+ /* Look things up ... */
+ err = hurd_file_name_lookup (&_hurd_ports_use, &getdport, lookup,
+ name, flags, mode & ~getumask (),
+ &node);
+
+ return err ? (__hurd_fail (err), MACH_PORT_NULL) : node;
+}
diff --git a/sutils/e2os.sh b/sutils/e2os.sh
new file mode 100755
index 00000000..10fe5087
--- /dev/null
+++ b/sutils/e2os.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+# Set/get the `creator_os' field of an ext2fs partition
+#
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+USAGE="Usage: $0 DEVICE [OS]"
+
+DD=${DD-/bin/dd}
+OD=${OD-/bin/od}
+SED=${SED-/bin/sed}
+AWK=${AWK-/bin/gawk}
+
+# Hack to allow this script to work well under linux too.
+test ! -x "$OD" -a -x /usr/bin/od && OD=/usr/bin/od
+test ! -x "$AWK" -a -x /usr/bin/gawk && AWK=/usr/bin/gawk
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "$USAGE"
+ echo "Get or set the creator_os parameter of an ext2fs partition."
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ exit 0;;
+ --usage)
+ echo "Usage: $0 [-V?] [--help] [--usage] [--version] DEVICE [OS]"
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_e2os_"; exit 0;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+case "$#" in 1 | 2) ;; # ok
+ *) echo 1>&2 "$USAGE"
+ echo 1>&2 "Try \`--help' for more information";
+ exit 1;;
+esac
+
+DEVICE="$1"; shift
+OS="$1"
+
+# Superblock fields (format is "BYTE_OFFS SIZE")
+SB_MAGIC="56 2"
+SB_OS="72 4"
+# Ext2fs magic numbers
+MAGIC_EXT2=ef53
+MAGIC_EXT2_OLD=ef53
+# Symbolic names for os types we know about
+OS_LINUX=0
+OS_HURD=1
+OS_MASIX=2
+OS_FREEBSD=3
+OS_LITES=4
+
+# Superblock
+SB=/tmp/,e2os-sb.$$
+
+# We have to store error output in a file so that we can filter it (for all
+# unix's stressing of pipelines, /bin/sh sure works hard to prevent you using
+# them).
+ERRS=/tmp/,e2os-errs.$$
+
+trap "/bin/rm -f $SB $ERRS" 0
+
+# Read the superblock
+$DD 2>"$ERRS" if="$DEVICE" of="$SB" bs=1k skip=1 count=1 \
+|| { $SED 1>&2 "s;^$DD:;$0:;" "$ERRS"; exit 2; }
+
+# Extract a word of SZ bytes from byte offset POS in the superblock
+# Optional arg FMT is what format to use (x = hex, d = decimal)
+function sbget
+{
+ local pos="$1" sz="$2" fmt="${3-d}"
+ pos=$(($pos / $sz))
+ $DD 2>/dev/null if="$SB" bs="$sz" skip="$pos" count=1 \
+ | $OD -An -t"$fmt$sz" \
+ | $SED 's;^[ 0]*\(.\);\1;'
+}
+
+# Set a word of SZ bytes at byte offset POS in the superblock to VAL
+function sbset
+{
+ local pos="$1" sz="$2" val="$3"
+ pos=$(($pos / $sz))
+ echo "$val" \
+ | $AWK '{ n=$1+0; printf ("%c%c%c%c", n, n/256, n/(2^16), n/(2^24)); }' \
+ | $DD 2>/dev/null of="$SB" bs="$sz" seek="$pos" count=1 conv=notrunc
+}
+
+# Check the magic number
+magic="`sbget $SB_MAGIC x`"
+case "$magic" in
+ $MAGIC_EXT2) ;; # ok
+ $MAGIC_EXT2_OLD) echo "$0: $DEVICE: Old-format ext2 filesystem"; exit 3;;
+ *) echo "$0: $DEVICE: Not an ext2 filesystem (magic = 0x$magic)"; exit 4;;
+esac
+
+if test "$OS"; then
+ # Set the os field
+ case "$OS" in
+ linux) OS=$OS_LINUX;;
+ hurd) OS=$OS_HURD;;
+ masix) OS=$OS_MASIX;;
+ freebsd) OS=$OS_FREEBSD;;
+ lites) OS=$OS_LITES;;
+ "*[!0-9]*")
+ echo 1>&2 "$0: $OS: Unknown ext2 creator_os value"; exit 5;;
+ esac
+
+ # Frob the superlock
+ sbset $SB_OS "$OS"
+
+ # Write the superblock
+ $DD 2>"$ERRS" if="$SB" of="$DEVICE" bs=1k seek=1 count=1 conv=notrunc \
+ || { $SED 1>&2 "s;^$DD:;$0:;" "$ERRS"; exit 6; }
+else
+ # Print the os field.
+ OS="`sbget $SB_OS`"
+ case "$OS" in
+ "") exit 2;;
+ $OS_LINUX) OS=linux;;
+ $OS_HURD) OS=hurd;;
+ $OS_MASIX) OS=masix;;
+ $OS_FREEBSD) OS=freebsd;;
+ $OS_LITES) OS=lites;;
+ esac
+ echo "$OS"
+fi
diff --git a/sutils/fsck.c b/sutils/fsck.c
new file mode 100644
index 00000000..424e3f17
--- /dev/null
+++ b/sutils/fsck.c
@@ -0,0 +1,568 @@
+/* Hurd-aware fsck wrapper
+
+ Copyright (C) 1996, 97, 98, 99 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This wrapper runs other file-system specific fsck programs. They are
+ expected to accept at least the following options:
+
+ -p Terse automatic mode
+ -y Automatically answer yes to all questions
+ -n Automatically answer no to all questions
+ -f Check even if clean
+ -s Only print diagostic messages
+
+ They should also return exit-status codes as following:
+
+ 0 Filesystem was clean
+ 1,2 Filesystem fixed (and is now clean)
+ 4,8 Filesystem was broken, but couldn't be fixed
+ ... Anything else is assumed be some horrible error
+
+ The exit-status from this wrapper is the greatest status returned from any
+ individual fsck.
+
+ Although it knows something about the hurd, this fsck still uses
+ /etc/fstab, and is generally not very integrated. That will have to wait
+ until the appropiate mechanisms for doing so are decided. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <error.h>
+#include <argp.h>
+#include <argz.h>
+#include <assert.h>
+#include <version.h>
+
+#include "fstab.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (fsck);
+
+
+/* for debugging */
+static int _debug = 0;
+#define debug(fmt, args...) \
+ do { if (_debug) { \
+ fprintf (stderr, "[%s: ", __FUNCTION__); \
+ fprintf (stderr, fmt , ##args); \
+ fprintf (stderr, "]\n"); } } while (0)
+#define fs_debug(fs, fmt, args...) \
+ debug ("%s: " fmt, (fs)->mntent.mnt_dir , ##args)
+
+#define FSCK_SEARCH_FMTS "/sbin/fsck.%s"
+
+/* Exit codes we return. */
+#define FSCK_EX_OK 0 /* No errors */
+#define FSCK_EX_FIXED 1 /* File system errors corrected */
+#define FSCK_EX_BROKEN 4 /* File system errors left uncorrected */
+#define FSCK_EX_QUIT 12 /* Got SIGQUIT */
+#define FSCK_EX_SIGNAL 20 /* Signalled (not SIGQUIT) */
+#define FSCK_EX_ERROR 50
+#define FSCK_EX_EXEC 99 /* Exec failed */
+/* Everything else is some sort of fsck problem. */
+
+/* Things we know about what child fsck's might return. */
+#define FSCK_EX_IS_FIXED(st) ({ int _st = (st); _st >= 1 || _st <= 2; })
+#define FSCK_EX_IS_BROKEN(st) ({ int _st = (st); _st >= 4 || _st <= 8; })
+
+/* Common fsck flags. */
+#define FSCK_F_PREEN 0x1
+#define FSCK_F_YES 0x2
+#define FSCK_F_NO 0x4
+#define FSCK_F_FORCE 0x8
+#define FSCK_F_SILENT 0x10
+
+/* The following are only used internally. */
+#define FSCK_F_VERBOSE 0x100
+#define FSCK_F_WRITABLE 0x200 /* Make writable after fscking. */
+#define FSCK_F_AUTO 0x400 /* Do all filesystems in fstab. */
+#define FSCK_F_DRYRUN 0x800 /* Don't actually do anything. */
+
+static int got_sigquit = 0, got_sigint = 0;
+
+static void sigquit ()
+{
+ got_sigquit = 1;
+}
+
+static void sigint ()
+{
+ got_sigint = 1;
+}
+
+struct fsck
+{
+ struct fs *fs; /* Filesystem being fscked. */
+ int pid; /* Pid for process. */
+ int make_writable; /* Make writable after fscking if possible. */
+ struct fsck *next, **self;
+};
+
+struct fscks
+{
+ struct fsck *running; /* Fsck processes now running. */
+ int free_slots; /* Number of fsck processes we can start. */
+ int flags;
+};
+
+/* Starts FS's fsck program on FS's device, returning the pid of the process.
+ If an error is encountered, prints an error message and returns 0.
+ Filesystems that need not be fscked at all also return 0 (but don't print
+ an error message). */
+static pid_t
+fs_start_fsck (struct fs *fs, int flags)
+{
+ pid_t pid;
+ char flags_buf[10];
+ char *argv[4], **argp = argv;
+ struct fstype *type;
+ error_t err = fs_type (fs, &type);
+
+ assert_perror (err); /* Should already have been checked for. */
+ assert (type->program);
+
+ *argp++ = type->program;
+
+ if (flags & (FSCK_F_PREEN|FSCK_F_YES|FSCK_F_NO|FSCK_F_FORCE|FSCK_F_SILENT))
+ {
+ char *p = flags_buf;
+ *argp++ = flags_buf;
+ *p++ = '-';
+ if (flags & FSCK_F_PREEN) *p++ = 'p';
+ if (flags & FSCK_F_YES) *p++ = 'y';
+ if (flags & FSCK_F_NO) *p++ = 'n';
+ if (flags & FSCK_F_FORCE) *p++ = 'f';
+ if (flags & FSCK_F_SILENT) *p++ = 's';
+ *p = '\0';
+ }
+
+ *argp++ = fs->mntent.mnt_fsname;
+ *argp = 0;
+
+ if (flags & FSCK_F_DRYRUN)
+ {
+ char *argz;
+ size_t argz_len;
+ argz_create (argv, &argz, &argz_len);
+ argz_stringify (argz, argz_len, ' ');
+ puts (argz);
+ free (argz);
+ return 0;
+ }
+
+ pid = fork ();
+ if (pid < 0)
+ {
+ error (0, errno, "fork");
+ return 0;
+ }
+
+ if (pid == 0)
+ /* Child. */
+ {
+ execv (type->program, argv);
+ exit (FSCK_EX_EXEC); /* Exec failed. */
+ }
+
+ if ((flags & FSCK_F_VERBOSE) || _debug)
+ {
+ char *argz;
+ size_t argz_len;
+ argz_create (argv, &argz, &argz_len);
+ argz_stringify (argz, argz_len, ' ');
+ fs_debug (fs, "Spawned pid %d: %s", pid, argz);
+ if (flags & FSCK_F_VERBOSE)
+ puts (argz);
+ free (argz);
+ }
+
+ return pid;
+}
+
+/* Start a fsck process for FS running, and add an entry for it to FSCKS.
+ This also ensures that if FS is currently mounted, it will be made
+ readonly first. If the fsck is successfully started, 0 is returned,
+ otherwise FSCK_EX_ERROR. */
+static int
+fscks_start_fsck (struct fscks *fscks, struct fs *fs)
+{
+ error_t err;
+ int mounted, make_writable;
+ struct fsck *fsck;
+
+ if (got_sigint)
+ /* We got SIGINT, so we pretend that all fscks got a signal without even
+ attempting to run them. */
+ {
+ fs_debug (fs, "Forcing signal");
+ return FSCK_EX_SIGNAL;
+ }
+
+#define CK(err, fmt, args...) \
+ do { if (err) { error (0, err, fmt , ##args); return FSCK_EX_ERROR; } } while (0)
+
+ fs_debug (fs, "Checking mounted state");
+ err = fs_mounted (fs, &mounted);
+ CK (err, "%s: Cannot check mounted state", fs->mntent.mnt_dir);
+
+ if (mounted)
+ {
+ int readonly;
+
+ fs_debug (fs, "Checking readonly state");
+ err = fs_readonly (fs, &readonly);
+ CK (err, "%s: Cannot check readonly state", fs->mntent.mnt_dir);
+
+ if (fscks->flags & FSCK_F_DRYRUN)
+ {
+ if (! readonly)
+ {
+ printf ("%s: writable filesystem %s would be made read-only\n",
+ program_invocation_name, fs->mntent.mnt_dir);
+ readonly = 1;
+ }
+ }
+
+ if (! readonly)
+ {
+ fs_debug (fs, "Making readonly");
+ err = fs_set_readonly (fs, 1);
+ CK (err, "%s: Cannot make readonly", fs->mntent.mnt_dir);
+ }
+
+ make_writable = !readonly
+ || ((fscks->flags & FSCK_F_WRITABLE) && hasmntopt (&fs->mntent, "rw"));
+ if (make_writable)
+ {
+ fs_debug (fs, "Will make writable after fscking if possible");
+ make_writable = 1;
+ }
+ }
+ else
+ make_writable = 0;
+
+#undef CK
+
+ /* Ok, any mounted filesystem is safely readonly. */
+
+ fsck = malloc (sizeof (struct fsck));
+ if (! fsck)
+ {
+ error (0, ENOMEM, "malloc");
+ return FSCK_EX_ERROR;
+ }
+
+ fsck->fs = fs;
+ fsck->make_writable = make_writable;
+ fsck->next = fscks->running;
+ if (fsck->next)
+ fsck->next->self = &fsck->next;
+ fsck->self = &fscks->running;
+ fsck->pid = fs_start_fsck (fs, fscks->flags);
+ fscks->running = fsck;
+
+ if (fsck->pid)
+ fscks->free_slots--;
+
+ return 0;
+}
+
+/* Cleanup after fscking with FSCK. If REMOUNT is true, ask the filesystem
+ to remount itself (to incorporate changes made by the fsck program). If
+ MAKE_WRITABLE is true, then if the filesystem should be made writable, do
+ so (after remounting if applicable). */
+static void
+fsck_cleanup (struct fsck *fsck, int remount, int make_writable)
+{
+ error_t err = 0;
+ struct fs *fs = fsck->fs;
+
+ /* Remove from chain. */
+ *fsck->self = fsck->next;
+ if (fsck->next)
+ fsck->next->self = fsck->self;
+
+ fs_debug (fs, "Cleaning up after fsck (remount = %d, make_writable = %d)",
+ remount, make_writable);
+
+ if (fs->mounted > 0)
+ /* It's currently mounted; if the fsck modified the device, tell the
+ running filesystem to remount it. Also we may make it writable. */
+ {
+ if (remount)
+ {
+ fs_debug (fs, "Remounting");
+ err = fs_remount (fs);
+ if (err)
+ error (0, err, "%s: Cannot remount", fs->mntent.mnt_dir);
+ }
+ if (!err && make_writable && fsck->make_writable)
+ {
+ fs_debug (fs, "Making writable");
+ err = fs_set_readonly (fs, 0);
+ if (err)
+ error (0, err, "%s: Cannot make writable", fs->mntent.mnt_dir);
+ }
+ }
+
+ free (fsck);
+}
+
+/* Wait for some fsck process to exit, cleaning up after it, and return its
+ exit-status. */
+static int
+fscks_wait (struct fscks *fscks)
+{
+ pid_t pid;
+ int wstatus, status;
+ struct fsck *fsck, *next;
+
+ /* Cleanup fscks that didn't even start. */
+ for (fsck = fscks->running; fsck; fsck = next)
+ {
+ next = fsck->next;
+ if (fsck->pid == 0)
+ {
+ fs_debug (fsck->fs, "Pruning failed fsck");
+ fsck_cleanup (fsck, 0, 1);
+ }
+ }
+
+ debug ("Waiting...");
+
+ do
+ pid = wait (&wstatus);
+ while (pid < 0 && errno == EINTR);
+
+ if (pid > 0)
+ {
+ if (WIFEXITED (wstatus))
+ status = WEXITSTATUS (wstatus);
+ else if (WIFSIGNALED (wstatus))
+ status = FSCK_EX_SIGNAL;
+ else
+ status = FSCK_EX_ERROR;
+
+ for (fsck = fscks->running; fsck; fsck = fsck->next)
+ if (fsck->pid == pid)
+ {
+ int remount = (status != 0);
+ int make_writable = (status == 0 || FSCK_EX_IS_FIXED (status));
+ fs_debug (fsck->fs, "Fsck finished (status = %d)", status);
+ fsck_cleanup (fsck, remount, make_writable);
+ fscks->free_slots++;
+ break;
+ }
+ if (! fsck)
+ error (0, 0, "%d: Unknown process exited", pid);
+ }
+ else if (errno == ECHILD)
+ /* There are apparently no child processes left, and we weren't told of
+ their demise. This can't happen. */
+ {
+ while (fscks->running)
+ {
+ error (0, 0, "%s: Fsck process disappeared!",
+ fscks->running->fs->mntent.mnt_fsname);
+ /* Be pessimistic -- remount the filesystem, but leave it
+ readonly. */
+ fsck_cleanup (fscks->running, 1, 0);
+ fscks->free_slots++;
+ }
+ status = FSCK_EX_ERROR;
+ }
+ else
+ status = FSCK_EX_ERROR; /* What happened? */
+
+ return status;
+}
+
+/* Fsck all the filesystems in FSTAB, with the flags in FLAGS, doing at most
+ MAX_PARALLEL parallel fscks. The greatest exit code returned by any one
+ fsck is returned. */
+static int
+fsck (struct fstab *fstab, int flags, int max_parallel)
+{
+ int pass;
+ struct fs *fs;
+ int autom = (flags & FSCK_F_AUTO);
+ int summary_status = 0;
+ struct fscks fscks = { running: 0, flags: flags };
+
+ void merge_status (int status)
+ {
+ if (status > summary_status)
+ summary_status = status;
+ }
+
+ /* Do in pass order; pass 0 is never run, it is reserved for "off". */
+ for (pass = 1; pass > 0; pass = fstab_next_pass (fstab, pass))
+ /* Submit all filesystems in the given pass, up to MAX_PARALLEL at a
+ time. There should currently be no fscks running. */
+ {
+ debug ("Pass %d", pass);
+
+ fscks.free_slots = max_parallel;
+
+ /* Try and fsck every filesystem in this pass. */
+ for (fs = fstab->entries; fs; fs = fs->next)
+ if (fs->mntent.mnt_passno == pass)
+ /* FS is applicable for this pass. */
+ {
+ struct fstype *type;
+ error_t err = fs_type (fs, &type);
+
+ if (err)
+ {
+ error (0, err, "%s: Cannot find fsck program (type %s)",
+ fs->mntent.mnt_dir, fs->mntent.mnt_type);
+ merge_status (FSCK_EX_ERROR);
+ }
+ else if (type->program)
+ /* This is a fsckable filesystem. */
+ {
+ fs_debug (fs, "Fsckable; free_slots = %d", fscks.free_slots);
+ while (fscks.free_slots == 0)
+ /* No room; wait for another fsck to finish. */
+ merge_status (fscks_wait (&fscks));
+ merge_status (fscks_start_fsck (&fscks, fs));
+ }
+ else if (autom)
+ fs_debug (fs, "Not fsckable");
+ else
+ error (0, 0, "%s: %s: Not a fsckable filesystem type",
+ fs->mntent.mnt_dir, fs->mntent.mnt_type);
+ }
+
+ /* Now wait for them all to finish. */
+ while (fscks.running)
+ merge_status (fscks_wait (&fscks));
+ }
+
+ return summary_status;
+}
+
+static const struct argp_option options[] =
+{
+ {"preen", 'p', 0, 0, "Terse automatic mode", 1},
+ {"yes", 'y', 0, 0, "Automatically answer yes to all questions"},
+ {"no", 'n', 0, 0, "Automatically answer no to all questions"},
+ {"parallel", 'l', "NUM", 0, "Limit the number of parallel checks to NUM"},
+ {"verbose", 'v', 0, 0, "Print informational messages"},
+ {"writable", 'w', 0, 0,
+ "Make RW filesystems writable after fscking, if possible"},
+ {"debug", 'D', 0, OPTION_HIDDEN },
+ {"force", 'f', 0, 0, "Check even if clean"},
+
+ {"dry-run", 'N', 0, 0, "Don't check, just show what would be done"},
+ {0, 0, 0, 0, "In --preen mode, the following also apply:", 2},
+ {"silent", 's', 0, 0, "Print only diagnostic messages"},
+ {"quiet", 'q', 0, OPTION_ALIAS | OPTION_HIDDEN },
+ {0, 0}
+};
+static const char doc[] = "Filesystem consistency check and repair";
+static const char args_doc[] = "[ DEVICE|FSYS... ]";
+
+
+int
+main (int argc, char **argv)
+{
+ struct fstab *check;
+ int status; /* exit status */
+ int flags = 0;
+ int max_parallel = -1; /* -1 => use default */
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ struct fstab_argp_params *params = state->input;
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = params; /* pass down to fstab_argp parser */
+ break;
+ case 'p': flags |= FSCK_F_PREEN; break;
+ case 'y': flags |= FSCK_F_YES; break;
+ case 'n': flags |= FSCK_F_NO; break;
+ case 'f': flags |= FSCK_F_FORCE; break;
+ case 's': flags |= FSCK_F_SILENT; break;
+ case 'v': flags |= FSCK_F_VERBOSE; break;
+ case 'w': flags |= FSCK_F_WRITABLE; break;
+ case 'N': flags |= FSCK_F_DRYRUN; break;
+ case 'D': _debug = 1; break;
+ case 'l':
+ max_parallel = atoi (arg);
+ if (max_parallel < 1)
+ argp_error (state, "%s: Invalid value for --max-parallel", arg);
+ break;
+ case ARGP_KEY_NO_ARGS:
+ if (flags & FSCK_F_PREEN)
+ params->do_all = 1;
+ else if (!params->do_all)
+ {
+ argp_usage (state);
+ return EINVAL;
+ }
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ static const struct argp_child kids[] =
+ { { &fstab_argp, 0,
+ "Filesystem selection (default is all in " _PATH_MNTTAB "):", 2 },
+ { 0 } };
+ struct argp argp = { options, parse_opt, args_doc, doc, kids };
+ struct fstab_argp_params fstab_params;
+
+ argp_parse (&argp, argc, argv, 0, 0, &fstab_params);
+
+ check = fstab_argp_create (&fstab_params,
+ FSCK_SEARCH_FMTS, sizeof FSCK_SEARCH_FMTS);
+ if (fstab_params.do_all)
+ flags |= FSCK_F_AUTO;
+
+ if (max_parallel <= 0)
+ {
+ if (flags & FSCK_F_PREEN)
+ max_parallel = 100; /* In preen mode, do lots in parallel. */
+ else
+ max_parallel = 1; /* Do one at a time to keep output rational. */
+ }
+
+ /* If the user send a SIGQUIT (usually ^\), then do all checks, but
+ regardless of their outcome, return a status that will cause the
+ automatic reboot to stop after fscking is complete. */
+ signal (SIGQUIT, sigquit);
+
+ /* Let currently running fscks complete (each such program can handle
+ signals as it sees fit), and cause not-yet-run fscks to act as if they
+ got a signal. */
+ signal (SIGINT, sigint);
+
+ debug ("Fscking...");
+ status = fsck (check, flags, max_parallel);
+ if (got_sigquit && status < FSCK_EX_QUIT)
+ status = FSCK_EX_QUIT;
+
+ exit (status);
+}
diff --git a/sutils/fstab.c b/sutils/fstab.c
new file mode 100644
index 00000000..4574d41d
--- /dev/null
+++ b/sutils/fstab.c
@@ -0,0 +1,956 @@
+/* Fstab filesystem frobbing
+
+ Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <error.h>
+#include <argz.h>
+#include <argp.h>
+#include <fnmatch.h>
+
+#include <hurd/fsys.h>
+
+#include "fstab.h"
+
+extern error_t fsys_set_readonly (fsys_t fsys, int readonly);
+extern error_t fsys_get_readonly (fsys_t fsys, int *readonly);
+extern error_t fsys_update (fsys_t fsys);
+
+extern file_t file_name_lookup_carefully (const char *file,
+ int flags, mode_t mode);
+
+/* Return a new fstab in FSTAB. */
+error_t
+fstab_create (struct fstypes *types, struct fstab **fstab)
+{
+ struct fstab *new = malloc (sizeof (struct fstab));
+ if (new)
+ {
+ new->entries = 0;
+ new->types = types;
+ *fstab = new;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Free FSTAB and all of its entries. */
+void
+fstab_free (struct fstab *fstab)
+{
+ while (fstab->entries)
+ fs_free (fstab->entries);
+ free (fstab);
+}
+
+/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */
+error_t
+fstypes_create (const char *search_fmts, size_t search_fmts_len,
+ struct fstypes **types)
+{
+ struct fstypes *new = malloc (sizeof (struct fstypes));
+ if (new)
+ {
+ new->entries = 0;
+ new->program_search_fmts = malloc (search_fmts_len);
+ new->program_search_fmts_len = search_fmts_len;
+ if (! new->program_search_fmts)
+ {
+ free (types);
+ return ENOMEM;
+ }
+ bcopy (search_fmts, new->program_search_fmts, search_fmts_len);
+ *types = new;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Return an fstype entry in TYPES called NAME, in FSTYPE. If there is no
+ existing entry, an attempt to find a fsck program with the given type,
+ using the alternatives in the FSCK_SEARCH_FMTS field in TYPES. If
+ one is found, it is added to TYPES, otherwise an new entry is created
+ with a NULL PROGRAM field. */
+error_t
+fstypes_get (struct fstypes *types, const char *name, struct fstype **fstype)
+{
+ char *fmts, *fmt;
+ size_t fmts_len;
+ struct fstype *type;
+ char *program = 0;
+
+ for (type = types->entries; type; type = type->next)
+ if (strcasecmp (type->name, name) == 0)
+ {
+ *fstype = type;
+ return 0;
+ }
+
+ /* No existing entry, make a new one. */
+
+ fmts = types->program_search_fmts;
+ fmts_len = types->program_search_fmts_len;
+
+ for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
+ {
+ int fd;
+
+ asprintf (&program, fmt, name);
+ fd = open (program, O_EXEC);
+ if (fd < 0)
+ {
+ free (program); /* Failed. */
+ if (errno != ENOENT && errno != EACCES)
+ /* The program's there but something went wrong; fail. */
+ return errno;
+ }
+ else
+ /* We can open for exec, but check the stat info too (e.g. root can
+ open everything). */
+ {
+ struct stat stat;
+ int rv = fstat (fd, &stat);
+
+ close (fd);
+
+ if (rv < 0)
+ {
+ free (program);
+ return errno;
+ }
+
+ if (stat.st_mode & S_IXUSR)
+ /* Yup execute bit is set. This must be a program... */
+ break;
+
+ free (program);
+ }
+
+ program = 0;
+ }
+
+ type = malloc (sizeof (struct fstype));
+ if (! type)
+ {
+ free (program);
+ return ENOMEM;
+ }
+
+ type->name = strdup (name);
+ if (type->name == 0)
+ {
+ free (type);
+ return ENOMEM;
+ }
+ type->program = program;
+ type->next = types->entries;
+ types->entries = type;
+
+ *fstype = type;
+
+ return 0;
+}
+
+#if 0
+/* XXX nice idea, but not that useful since scanf's %s always eats all
+ non-ws, and it seems a bit overkill to convert it to a .+ regexp match */
+error_t
+fstypes_find_program (struct fstypes *types, const char *program,
+ struct fstype **fstype)
+{
+ char *fmts, *fmt;
+ size_t fmts_len;
+ struct fstype *type;
+ char *typename;
+
+ /* First see if a known type matches this program. */
+ for (type = types->entries; type; type = type->next)
+ if (type->program && !strcmp (type->program, program))
+ {
+ *fstype = type;
+ return 0;
+ }
+
+ /* No existing entry, see if we can make a new one. */
+
+ typename = alloca (strlen (program) + 1);
+
+ fmts = types->program_search_fmts;
+ fmts_len = types->program_search_fmts_len;
+ for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
+ /* XXX this only works for trailing %s */
+ if (sscanf (program, fmt, typename) == 1)
+ {
+ /* This format matches the program and yields the type name.
+ Create a new entry for this type. */
+
+ type = malloc (sizeof (struct fstype));
+ if (! type)
+ return ENOMEM;
+ type->name = strdup (typename);
+ if (type->name == 0)
+ {
+ free (type);
+ return ENOMEM;
+ }
+ type->program = strdup (program);
+ if (type->program == 0)
+ {
+ free (type->name);
+ free (type);
+ return ENOMEM;
+ }
+ type->next = types->entries;
+ types->entries = type;
+
+ *fstype = type;
+ return 0;
+ }
+
+ /* We could find no program search format that could have yielded this
+ program name. */
+ *fstype = 0;
+ return 0;
+}
+#endif
+
+/* Copy MNTENT into FS, copying component strings as well. */
+error_t
+fs_set_mntent (struct fs *fs, const struct mntent *mntent)
+{
+ char *end;
+ size_t needed = 0;
+
+ if (fs->storage)
+ free (fs->storage);
+
+ /* Allocate space for all string mntent fields in FS. */
+#define COUNT(field) if (mntent->field) needed += strlen (mntent->field) + 1;
+ COUNT (mnt_fsname);
+ COUNT (mnt_dir);
+ COUNT (mnt_type);
+ COUNT (mnt_opts);
+#undef COUNT
+
+ fs->storage = malloc (needed);
+ if (! fs->storage)
+ return ENOMEM;
+
+ if (!fs->mntent.mnt_dir || !mntent->mnt_dir
+ || strcmp (fs->mntent.mnt_dir, mntent->mnt_dir) != 0)
+ {
+ fs->mounted = fs->readonly = -1;
+ if (fs->fsys != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), fs->fsys);
+ fs->fsys = MACH_PORT_NULL;
+ }
+
+ /* Copy MNTENT into FS; string-valued fields will be fixed up next. */
+ fs->mntent = *mntent;
+
+ /* Copy each mntent field from MNTENT into FS's version. */
+ end = fs->storage;
+#define STORE(field) \
+ fs->mntent.field = end; end = stpcpy (end, mntent->field) + 1
+ STORE (mnt_fsname);
+ STORE (mnt_dir);
+ STORE (mnt_type);
+ STORE (mnt_opts);
+#undef STORE
+
+ if (fs->type
+ && (!mntent->mnt_type
+ || strcasecmp (fs->type->name, mntent->mnt_type) != 0))
+ fs->type = 0; /* Type is different. */
+
+ return 0;
+}
+
+/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
+ necessary. */
+error_t
+fs_type (struct fs *fs, struct fstype **type)
+{
+ error_t err = 0;
+ if (! fs->type)
+ err = fstypes_get (fs->fstab->types, fs->mntent.mnt_type, &fs->type);
+ if (! err)
+ *type = fs->type;
+ return err;
+}
+
+/* Looks to see if FS is currently mounted, being very careful to avoid
+ mounting anything that's not already, and fills in the fsys & mounted
+ fields in FS. */
+static error_t
+_fs_check_mounted (struct fs *fs)
+{
+ error_t err = 0;
+
+ if (fs->mounted < 0)
+ /* The mounted field in FS is -1 if we're not sure. */
+ {
+ if (fs->fsys != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), fs->fsys);
+
+ if (strcmp (fs->mntent.mnt_dir, "/") == 0)
+ /* The root is always mounted. Get its control port. */
+ {
+ file_t root = getcrdir ();
+ if (root == MACH_PORT_NULL)
+ err = errno;
+ else
+ {
+ err = file_getcontrol (root, &fs->fsys);
+ mach_port_deallocate (mach_task_self (), root);
+ }
+ }
+ else
+ {
+ file_t mount_point =
+ file_name_lookup_carefully (fs->mntent.mnt_dir, O_NOTRANS, 0);
+
+ if (mount_point != MACH_PORT_NULL)
+ /* The node exists. Is it the root of an active translator?
+ [Note that it could be a different translator than the one in
+ the mntent, but oh well, nothing we can do about that.] */
+ {
+ err = file_get_translator_cntl (mount_point, &fs->fsys);
+ if (err == EINVAL || err == EOPNOTSUPP || err == ENXIO)
+ /* Either the mount point doesn't exist, or wasn't mounted. */
+ {
+ fs->fsys = MACH_PORT_NULL;
+ err = 0;
+ }
+ }
+ else if (errno == ENXIO)
+ /* Ran into an inactive passive translator. FS can't be mounted. */
+ {
+ fs->fsys = MACH_PORT_NULL;
+ err = 0;
+ }
+ }
+
+ if (! err)
+ fs->mounted = (fs->fsys != MACH_PORT_NULL);
+ }
+
+ return err;
+}
+
+/* Looks to see if FS is currently mounted, being very careful to avoid
+ mounting anything that's not already, and returns the control port for the
+ mounted filesystem (MACH_PORT_NULL if not mounted). */
+error_t
+fs_fsys (struct fs *fs, fsys_t *fsys)
+{
+ error_t err = _fs_check_mounted (fs);
+ if (!err && fsys)
+ *fsys = fs->fsys;
+ return err;
+}
+
+/* Looks to see if FS is currently mounted, being very careful to avoid
+ mounting anything that's not already, and returns the boolean MOUNTED. */
+error_t
+fs_mounted (struct fs *fs, int *mounted)
+{
+ error_t err = _fs_check_mounted (fs);
+ if (!err && mounted)
+ *mounted = fs->mounted;
+ return err;
+}
+
+/* Looks to see if FS is currently mounted readonly, being very careful to
+ avoid mounting anything that's not already, and returns the boolean
+ READONLY. If FS isn't mounted at all, READONLY is set to 1 (it's not
+ going to write anything!). */
+error_t
+fs_readonly (struct fs *fs, int *readonly)
+{
+ error_t err = 0;
+
+ if (fs->readonly < 0)
+ /* Unknown. */
+ {
+ fsys_t fsys;
+
+ err = fs_fsys (fs, &fsys);
+ if (! err)
+ {
+ if (fsys == MACH_PORT_NULL)
+ fs->readonly = 1;
+ else
+ err = fsys_get_readonly (fsys, &fs->readonly);
+ }
+ }
+
+ if (!err && readonly)
+ *readonly = fs->readonly;
+
+ return err;
+}
+
+/* If FS is currently mounted writable, try to make it readonly. XXX If FS
+ is not mounted at all, then nothing is done. */
+error_t
+fs_set_readonly (struct fs *fs, int readonly)
+{
+ int currently_readonly;
+ error_t err = fs_readonly (fs, &currently_readonly);
+
+ readonly = !!readonly;
+
+ if (!err && readonly != currently_readonly)
+ /* We have to try and change the readonly state. */
+ {
+ fsys_t fsys;
+ err = fs_fsys (fs, &fsys);
+ if (!err && fsys != MACH_PORT_NULL) /* XXX What to do if not mounted? */
+ err = fsys_set_readonly (fsys, readonly);
+ if (! err)
+ fs->readonly = readonly;
+ }
+
+ return err;
+}
+
+/* If FS is currently mounted tell it to remount the device. XXX If FS is
+ not mounted at all, then nothing is done. */
+error_t
+fs_remount (struct fs *fs)
+{
+ fsys_t fsys;
+ error_t err = fs_fsys (fs, &fsys);
+ if (!err && fsys != MACH_PORT_NULL) /* XXX What to do if not mounted? */
+ err = fsys_update (fsys);
+ return err;
+}
+
+/* Returns the FS entry in FSTAB with the device field NAME (there can only
+ be one such entry). */
+inline struct fs *
+fstab_find_device (const struct fstab *fstab, const char *name)
+{
+ struct fs *fs;
+ for (fs = fstab->entries; fs; fs = fs->next)
+ if (strcmp (fs->mntent.mnt_fsname, name) == 0)
+ return fs;
+ return 0;
+}
+
+/* Returns the FS entry in FSTAB with the mount point NAME (there can only
+ be one such entry). */
+inline struct fs *
+fstab_find_mount (const struct fstab *fstab, const char *name)
+{
+ struct fs *fs;
+
+ /* Don't count "none" or "-" as matching any other mount point.
+ It is canonical to use "none" for swap partitions, and multiple
+ such do not in fact conflict with each other. Likewise, the
+ special device name "ignore" is used for things that should not
+ be processed automatically. */
+ if (!strcmp (name, "-")
+ || !strcmp (name, "none")
+ || !strcmp (name, "ignore"))
+ return 0;
+
+ for (fs = fstab->entries; fs; fs = fs->next)
+ if (strcmp (fs->mntent.mnt_dir, name) == 0)
+ return fs;
+ return 0;
+}
+
+/* Returns the FS entry in FSTAB with the device or mount point NAME (there
+ can only be one such entry). */
+inline struct fs *
+fstab_find (const struct fstab *fstab, const char *name)
+{
+ return fstab_find_device (fstab, name) ?: fstab_find_mount (fstab, name);
+}
+
+/* Cons FS onto the beginning of FSTAB's entry list. */
+static void
+_fstab_add (struct fstab *fstab, struct fs *fs)
+{
+ fs->fstab = fstab;
+ fs->next = fstab->entries;
+ fs->self = &fstab->entries;
+ if (fstab->entries)
+ fstab->entries->self = &fs->next;
+ fstab->entries = fs;
+}
+
+/* Destroy FS, removing it from its containing FSTAB. */
+void
+fs_free (struct fs *fs)
+{
+ *fs->self = fs->next; /* unlink from chain */
+ if (fs->storage)
+ free (fs->storage);
+ if (fs->fsys != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), fs->fsys);
+ free (fs);
+}
+
+/* Add an entry for MNTENT to FSTAB, removing any existing entries that
+ conflict (in either the device or mount point). If RESULT is non-zero, the
+ new entry is returne in it. */
+error_t
+fstab_add_mntent (struct fstab *const fstab, const struct mntent *mntent,
+ struct fs **result)
+{
+ int new = 0; /* True if we didn't overwrite an old entry. */
+ error_t err = 0;
+ struct fs *fs = fstab_find_device (fstab, mntent->mnt_fsname);
+ struct fs *mounted_fs = fstab_find_mount (fstab, mntent->mnt_dir);
+
+ if (! fs)
+ /* No old entry with the same device; see if there's one with the same
+ mount point. */
+ {
+ fs = mounted_fs;
+ mounted_fs = 0;
+ }
+
+ if (! fs)
+ /* No old entry, make a new one. */
+ {
+ fs = malloc (sizeof (struct fs));
+ if (fs)
+ {
+ bzero (fs, sizeof (struct fs));
+ fs->mounted = fs->readonly = -1;
+ fs->fsys = MACH_PORT_NULL;
+ new = 1;
+ }
+ else
+ err = ENOMEM;
+ }
+
+ if (! err)
+ /* Try and fill in FS's mntent. */
+ err = fs_set_mntent (fs, mntent);
+
+ if (new)
+ {
+ if (! err)
+ _fstab_add (fstab, fs);
+ else if (fs)
+ free (fs);
+ }
+
+ if (!err && mounted_fs)
+ /* Get rid of the conflicting entry MOUNTED_FS. */
+ fs_free (mounted_fs);
+
+ if (!err && result)
+ *result = fs;
+
+ return err;
+}
+
+/* Copy the entry FS (which should belong to another fstab than DST) into
+ DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
+ COPY is non-zero, the copy is returned in it. */
+error_t
+fstab_add_fs (struct fstab *dst, const struct fs *fs, struct fs **copy)
+{
+ error_t err;
+ struct fs *new;
+ struct fstab *src = fs->fstab;
+
+ if (dst->types != src->types)
+ return EINVAL;
+
+ err = fstab_add_mntent (dst, &fs->mntent, &new);
+ if (err)
+ return err;
+
+ new->type = fs->type;
+
+ if (copy)
+ *copy = new;
+
+ return 0;
+}
+
+/* Merge SRC into DST, as if by calling fstab_add_fs on DST with every
+ entry in SRC, and then deallocating SRC. If DST & SRC have different
+ TYPES fields, EINVAL is returned. */
+error_t
+fstab_merge (struct fstab *dst, struct fstab *src)
+{
+ struct fs *fs;
+
+ if (dst->types != src->types)
+ return EINVAL;
+
+ /* Remove entries in DST which conflict with those in SRC. */
+ for (fs = src->entries; fs; fs = fs->next)
+ {
+ struct fs *old_fs;
+
+ old_fs = fstab_find_device (dst, fs->mntent.mnt_fsname);
+ if (old_fs)
+ fs_free (old_fs);
+ old_fs = fstab_find_mount (dst, fs->mntent.mnt_dir);
+ if (old_fs)
+ fs_free (old_fs);
+ }
+
+ /* Now that we know there are no conflicts, steal all SRC's entries and
+ cons them onto DST. */
+ for (fs = src->entries; fs; fs = fs->next)
+ _fstab_add (dst, fs);
+
+ /* Now all entries from SRC should be in DST, so just deallocate SRC. */
+ free (src);
+
+ return 0;
+}
+
+/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
+ duplicating one already in FS_LIST supersede the existing entry. */
+error_t
+fstab_read (struct fstab *fstab, const char *name)
+{
+ error_t err;
+ /* Used to hold entries from the file, before merging with FSTAB at the
+ end. */
+ struct fstab *contents;
+ FILE *stream = setmntent (name, "r");
+
+ if (! stream)
+ return errno;
+
+ err = fstab_create (fstab->types, &contents);
+ if (! err)
+ {
+ while (!err && !feof (stream))
+ {
+ struct mntent *mntent = getmntent (stream);
+
+ if (! mntent)
+ err = errno;
+ else if (fstab_find_device (fstab, mntent->mnt_fsname))
+ error (0, 0, "%s: Warning: duplicate entry for device %s (%s)",
+ name, mntent->mnt_fsname, mntent->mnt_dir);
+ else if (fstab_find_mount (fstab, mntent->mnt_dir))
+ error (0, 0, "%s: Warning: duplicate entry for mount point %s (%s)",
+ name, mntent->mnt_dir, mntent->mnt_fsname);
+ else
+ err = fstab_add_mntent (fstab, mntent, 0);
+ }
+
+ if (! err)
+ fstab_merge (fstab, contents);
+ else
+ fstab_free (contents);
+ }
+
+ endmntent (stream);
+
+ return err;
+}
+
+/* Return the next pass number that applies to any filesystem in FSTAB that
+ is greater than PASS, or -1 if there isn't any. */
+int fstab_next_pass (const struct fstab *fstab, int pass)
+{
+ int next_pass = -1;
+ struct fs *fs;
+ for (fs = fstab->entries; fs; fs = fs->next)
+ if (fs->mntent.mnt_passno > pass)
+ if (next_pass < 0 || fs->mntent.mnt_passno < next_pass)
+ {
+ next_pass = fs->mntent.mnt_passno;
+ if (next_pass == pass + 1)
+ break; /* Only possible answer. */
+ }
+ return next_pass;
+}
+
+
+static const struct argp_option options[] =
+{
+ {"all", 'a', 0, 0, "Do all filesystems in " _PATH_MNTTAB},
+ {0, 'A', 0, OPTION_ALIAS },
+ {"fstab", 'F', "FILE", 0, "File to use instead of " _PATH_MNTTAB},
+ {"fstype", 't', "TYPE", 0, "Do only filesystems of given type(s)"},
+ {"exclude-root",'R',0, 0,
+ "Exclude root (/) filesystem from " _PATH_MNTTAB " list"},
+ {"exclude", 'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
+
+ {"search-fmts",'S', "FMTS", 0,
+ "`:' separated list of formats to use for finding"
+ " filesystem-specific programs"},
+
+ {0, 0}
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ error_t err;
+ struct fstab_argp_params *params = state->input;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize our parsing state. */
+ if (! params)
+ return EINVAL; /* Need at least a way to return a result. */
+ bzero (params, sizeof *params);
+ break;
+
+ case 'A':
+ case 'a':
+ params->do_all = 1;
+ break;
+
+ case 'F':
+ params->fstab_path = arg;
+ break;
+
+ case 'S':
+ argz_create_sep (arg, ':',
+ &params->program_search_fmts,
+ &params->program_search_fmts_len);
+ break;
+
+ case 'R':
+ arg = "/";
+ /* FALLTHROUGH */
+ case 'X':
+ err = argz_add (&params->exclude, &params->exclude_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+ case 't':
+ err = argz_add_sep (&params->types, &params->types_len, arg, ',');
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_ARG:
+ err = argz_add (&params->names, &params->names_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_END:
+ /* Check for bogus combinations of arguments. */
+ if (params->names)
+ {
+ if (params->do_all)
+ argp_error (state, "filesystem arguments not allowed with --all");
+ if (params->exclude)
+ argp_error (state,
+ "--exclude not allowed with filesystem arguments");
+ if (params->types)
+ argp_error (state,
+ "--fstype not allowed with filesystem arguments");
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+const struct argp fstab_argp = {options, parse_opt, 0, 0};
+
+struct fstab *
+fstab_argp_create (struct fstab_argp_params *params,
+ const char *default_search_fmts,
+ size_t default_search_fmts_len)
+{
+ error_t err;
+ struct fstab *fstab, *check;
+ struct fstypes *types;
+
+ if (params->fstab_path == 0)
+ params->fstab_path = _PATH_MNTTAB;
+ if (params->program_search_fmts == 0)
+ {
+ params->program_search_fmts = (char *) default_search_fmts;
+ params->program_search_fmts_len = default_search_fmts_len;
+ }
+
+ err = fstypes_create (params->program_search_fmts,
+ params->program_search_fmts_len,
+ &types);
+ if (err)
+ error (102, err, "fstypes_create");
+
+ err = fstab_create (types, &fstab);
+ if (err)
+ error (101, err, "fstab_create");
+
+ err = fstab_read (fstab, params->fstab_path);
+ if (err)
+ error (103, err, "%s", params->fstab_path);
+
+ if (params->names)
+ {
+ /* Process specified filesystems; also look at /var/run/mtab. */
+ const char *name;
+
+ err = fstab_read (fstab, _PATH_MOUNTED);
+ if (err && err != ENOENT)
+ error (104, err, "%s", _PATH_MOUNTED);
+
+ err = fstab_create (types, &check);
+ if (err)
+ error (105, err, "fstab_create");
+
+ for (name = params->names; name; name = argz_next (params->names,
+ params->names_len,
+ name))
+ {
+ struct fs *fs = fstab_find (fstab, name);
+ if (! fs)
+ error (106, 0, "%s: Unknown device or filesystem", name);
+ fstab_add_fs (check, fs, 0);
+ }
+
+ /* fstab_free (fstab); XXX */
+ }
+ else
+ {
+ /* Process everything in /etc/fstab. */
+
+ if (params->exclude == 0 && params->types == 0)
+ check = fstab;
+ else
+ {
+ struct fs *fs;
+ const char *tn;
+ unsigned int nonexclude_types;
+
+ err = fstab_create (types, &check);
+ if (err)
+ error (105, err, "fstab_create");
+
+ /* For each excluded type (i.e. `-t notype'), clobber the
+ fstype entry's program with an empty string to mark it. */
+ nonexclude_types = 0;
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ {
+ if (!strncasecmp (tn, "no", 2))
+ {
+ struct fstype *type;
+ err = fstypes_get (types, &tn[2], &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ free (type->program);
+ type->program = strdup ("");
+ }
+ else
+ ++nonexclude_types;
+ }
+
+ if (nonexclude_types != 0)
+ {
+ const char *tn;
+ struct fstypes *wanttypes;
+
+ /* We will copy the types we want to include into a fresh
+ list in WANTTYPES. Since we specify no search formats,
+ `fstypes_get' applied to WANTTYPES can only create
+ elements with a null `program' field. */
+ err = fstypes_create (0, 0, &wanttypes);
+ if (err)
+ error (102, err, "fstypes_create");
+
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ if (strncasecmp (tn, "no", 2))
+ {
+ struct fstype *type;
+ err = fstypes_get (types, tn, &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ if (type->program == 0)
+ error (0, 0,
+ "requested filesystem type `%s' unknown", tn);
+ else
+ {
+ struct fstype *newtype = malloc (sizeof *newtype);
+ newtype->name = strdup (type->name);
+ newtype->program = strdup (type->program);
+ newtype->next = wanttypes->entries;
+ wanttypes->entries = newtype;
+ }
+ }
+
+ /* fstypes_free (types); */
+ types = wanttypes;
+ }
+
+ for (fs = fstab->entries; fs; fs = fs->next)
+ {
+ const char *ptn;
+ struct fstype *type;
+
+ err = fs_type (fs, &type);
+ if (err || nonexclude_types)
+ {
+ err = fstypes_get (types, fs->mntent.mnt_type, &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ if (params->types != 0)
+ continue;
+ }
+ if (nonexclude_types && type->program == 0)
+ continue; /* Freshly created, was not in WANTTYPES. */
+ if (type->program != 0 && type->program[0] == '\0')
+ continue; /* This type is marked as excluded. */
+
+ for (ptn = params->exclude; ptn;
+ ptn = argz_next (params->exclude, params->exclude_len, ptn))
+ if (fnmatch (ptn, fs->mntent.mnt_dir, 0) == 0)
+ break;
+ if (ptn) /* An exclude pattern matched. */
+ continue;
+
+ err = fstab_add_fs (check, fs, 0);
+ if (err)
+ error (107, err, "fstab_add_fs");
+ }
+
+ /* fstab_free (fstab); XXX */
+ }
+ }
+
+ return check;
+}
diff --git a/sutils/fstab.h b/sutils/fstab.h
new file mode 100644
index 00000000..ddd1656c
--- /dev/null
+++ b/sutils/fstab.h
@@ -0,0 +1,178 @@
+/* Fstab filesystem frobbing
+
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __FSTAB_H__
+#define __FSTAB_H__
+
+#include <mntent.h>
+#include <hurd.h>
+
+struct fs
+{
+ struct fstab *fstab; /* Containing fstab. */
+ struct mntent mntent; /* Mount entry from fstab file. */
+ char *storage; /* Storage for strings in MNTENT. */
+ struct fstype *type; /* Only set if fs_type called. */
+ int readonly, mounted; /* Only set if fs_{readonly,mounted} called.
+ 0 or 1 if known; -1 if unknown. */
+ fsys_t fsys; /* Only set if fs_fsys called. */
+ struct fs *next, **self;
+};
+
+struct fstab
+{
+ struct fs *entries;
+ struct fstypes *types;
+};
+
+struct fstype
+{
+ char *name; /* Malloced. */
+ char *program; /* Malloced. */
+ struct fstype *next;
+};
+
+struct fstypes
+{
+ struct fstype *entries;
+
+ /* How to search for programs. A '\0' separated list of strings. Each
+ should be a printf-style format string, which will be passed the
+ filesystem type. The first such expansion that results in an executable
+ file will be chosen as the fsck program for that type. */
+ char *program_search_fmts;
+ size_t program_search_fmts_len; /* Length of PROGRAM_SEARCH_FMTS. */
+};
+
+/* Return a new fstab in FSTAB. */
+error_t fstab_create (struct fstypes *types, struct fstab **fstab);
+
+/* Free FSTAB and all of its entries. */
+void fstab_free (struct fstab *fstab);
+
+/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */
+error_t fstypes_create (const char *search_fmts, size_t search_fmts_len,
+ struct fstypes **types);
+
+/* Return an fstype entry in TYPES called NAME, in FSTYPE. If there is no
+ existing entry, an attempt to find a program with the given type,
+ using the alternatives in the PROGRAM_SEARCH_FMTS field in TYPES. If
+ one is found, it is added to TYPES, otherwise a new entry is created
+ with a null PROGRAM field. */
+error_t fstypes_get (struct fstypes *types,
+ const char *name, struct fstype **fstype);
+
+/* Copy MNTENT into FS, copying component strings as well. */
+error_t fs_set_mntent (struct fs *fs, const struct mntent *mntent);
+
+/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
+ necessary. */
+error_t fs_type (struct fs *fs, struct fstype **type);
+
+/* Looks to see if FS is currently mounted, being very careful to avoid
+ mounting anything that's not already, and returns the control port for the
+ mounted filesystem (MACH_PORT_NULL if not mounted). */
+error_t fs_fsys (struct fs *fs, fsys_t *fsys);
+
+/* Looks to see if FS is currently mounted, being very careful to avoid
+ mounting anything that's not already, and returns the boolean MOUNTED. */
+error_t fs_mounted (struct fs *fs, int *mounted);
+
+/* Looks to see if FS is currently mounted readonly, being very careful to
+ avoid mounting anything that's not already, and returns the boolean
+ READONLY. If FS isn't mounted at all, READONLY is set to 1 (it's not
+ going to write anything!). */
+error_t fs_readonly (struct fs *fs, int *readonly);
+
+/* If FS is currently mounted writable, try to make it readonly. XXX If FS
+ is not mounted at all, then nothing is done. */
+error_t fs_set_readonly (struct fs *fs, int readonly);
+
+/* If FS is currently mounted tell it to remount the device. XXX If FS is
+ not mounted at all, then nothing is done. */
+error_t fs_remount (struct fs *fs);
+
+/* Destroy FS, removing it from its containing FSTAB. */
+void fs_free (struct fs *fs);
+
+/* Returns the FS entry in FSTAB with the device field NAME (there can only
+ be one such entry). */
+struct fs *fstab_find_device (const struct fstab *fstab, const char *name);
+
+/* Returns the FS entry in FSTAB with the mount point NAME (there can only
+ be one such entry). */
+struct fs *fstab_find_mount (const struct fstab *fstab, const char *name);
+
+/* Returns the FS entry in FSTAB with the device or mount point NAME (there
+ can only be one such entry). */
+struct fs *fstab_find (const struct fstab *fstab, const char *name);
+
+/* Add an entry for MNTENT to FSTAB, removing any existing entries that
+ conflict (in either the device or mount point). If RESULT is non-zero, the
+ new entry is returned in it. */
+error_t fstab_add_mntent (struct fstab *fstab, const struct mntent *mntent,
+ struct fs **result);
+
+/* Copy the entry FS (which should belong to another fstab than DST) into
+ DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
+ COPY is non-zero, the copy is returned in it. */
+error_t fstab_add_fs (struct fstab *dst, const struct fs *fs,
+ struct fs **copy);
+
+/* Merge SRC into DST, as if by calling fstab_add_fs on DST with every
+ entry in SRC, and then deallocating SRC. If DST & SRC have different
+ TYPES fields, EINVAL is returned. */
+error_t fstab_merge (struct fstab *dst, struct fstab *src);
+
+/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
+ duplicating one already in FS_LIST supersede the existing entry. */
+error_t fstab_read (struct fstab *fstab, const char *name);
+
+/* Return the next pass number that applies to any filesystem in FSTAB that
+ is greater than PASS, or -1 if there isn't any. */
+int fstab_next_pass (const struct fstab *fstab, int pass);
+
+
+struct argp;
+extern const struct argp fstab_argp;
+struct fstab_argp_params
+{
+ char *fstab_path;
+ char *program_search_fmts;
+ size_t program_search_fmts_len;
+
+ int do_all;
+ char *types;
+ size_t types_len;
+ char *exclude;
+ size_t exclude_len;
+
+ char *names;
+ size_t names_len;
+};
+
+struct fstab *fstab_argp_create (struct fstab_argp_params *params,
+ const char *default_search_fmts,
+ size_t default_search_fmts_len);
+
+
+#endif /* __FSTAB_H__ */
diff --git a/sutils/halt.c b/sutils/halt.c
new file mode 100644
index 00000000..01f06b4f
--- /dev/null
+++ b/sutils/halt.c
@@ -0,0 +1,39 @@
+/* Halt the system
+ Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <sys/reboot.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <argp.h>
+#include <hurd.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (halt);
+
+int
+main (int argc, char *argv[])
+{
+ struct argp argp = {0, 0, 0, "Halt the system"};
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+ reboot (RB_HALT);
+ perror ("reboot");
+ return 1;
+}
diff --git a/sutils/losetup.sh b/sutils/losetup.sh
new file mode 100644
index 00000000..85734571
--- /dev/null
+++ b/sutils/losetup.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# This script is roughly compatible with the Linux `losetup' utility.
+# The Hurd's `storeio' translator provides the equivalent functionality
+# (and a whole lot more), and of course works on any old file you want
+# to translate, not just magical "/dev/loopN" device files.
+#
+
+PATH=/bin
+
+usage() {
+ echo >&2 ...
+ exit 1
+}
+
+offset=0
+while [ $# -gt 0 ]; do
+ case "$arg" in
+ -d)
+ [ $# -eq 2 ] || usage
+ exec settrans -g -- "$2" /hurd/null
+ ;;
+ -e)
+ echo >&2 "$0: encryption not supported"
+ exit 3
+ ;;
+ -o)
+ [ $# -gt 1 ] || usage
+ offset="$1"
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+[ $# -eq 2 ] || usage
+device="$1"
+file="$2"
+
+# If the device name is "/dev/loopN", then create it if necessary. (?)
+create=
+case "$device" in
+'/dev/loop[0-9]*') ;; # smarty pants
+/dev/loop[0-9]*) create=--create ;;
+esac
+
+type='-Tfile '
+if [ "$offset" != 0 ]; then
+ blksz=`storeinfo -B -- "$file"`
+ if [ $[ $offset % $blksz ] -ne 0 ]; then
+ echo >&2 "$0: offset $offset is not a multiple of device block size $blksz"
+ exit 1
+ fi
+ type="-Tremap $[ $offset / $blksz ]+:file:"
+fi
+
+exec settrans $create -gap -- "${device}" /hurd/storeio ${type}"${file}"
diff --git a/sutils/reboot.c b/sutils/reboot.c
new file mode 100644
index 00000000..715dc90c
--- /dev/null
+++ b/sutils/reboot.c
@@ -0,0 +1,39 @@
+/* Reboot the system
+ Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <sys/reboot.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <argp.h>
+#include <hurd.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (reboot);
+
+int
+main (int argc, char *argv[])
+{
+ struct argp argp = {0, 0, 0, "Reboot the system"};
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+ reboot (0);
+ perror ("reboot");
+ return 1;
+}
diff --git a/sutils/swapoff.c b/sutils/swapoff.c
new file mode 100644
index 00000000..42521257
--- /dev/null
+++ b/sutils/swapoff.c
@@ -0,0 +1,2 @@
+#define SWAPOFF
+#include "swapon.c"
diff --git a/sutils/swapon.c b/sutils/swapon.c
new file mode 100644
index 00000000..fb264bc6
--- /dev/null
+++ b/sutils/swapon.c
@@ -0,0 +1,165 @@
+/* Add/remove paging devices
+
+ Copyright (C) 1997,98,99 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <argp.h>
+#include <error.h>
+#include <hurd/store.h>
+#include <version.h>
+#include <mach/default_pager.h>
+#include <mntent.h>
+
+#ifdef SWAPOFF
+const char *argp_program_version = STANDARD_HURD_VERSION (swapoff);
+#else
+const char *argp_program_version = STANDARD_HURD_VERSION (swapon);
+#endif
+
+static struct argp_option options[] =
+{
+ {"standard", 'a', 0, 0,
+ "Use all devices marked as `swap' in " _PATH_MNTTAB},
+ {0, 0}
+};
+static char *args_doc = "DEVICE...";
+
+#ifdef SWAPOFF
+static char *doc = "Stop paging on DEVICE...";
+#else
+static char *doc = "Start paging onto DEVICE...";
+#endif
+
+static int
+swaponoff (const char *file, int add)
+{
+ error_t err;
+ struct store *store;
+ static mach_port_t def_pager = MACH_PORT_NULL;
+ static mach_port_t dev_master = MACH_PORT_NULL;
+
+ err = store_open (file, 0, 0, &store);
+ if (err)
+ {
+ error (0, err, "%s", file);
+ return err;
+ }
+
+ if (store->class != &store_device_class)
+ {
+ error (0, 0, "%s: Can't get device", file);
+ return err;
+ }
+ if (! (store->flags & STORE_ENFORCED))
+ {
+ error (0, 0, "%s: Can only page to the entire device", file);
+ return err;
+ }
+
+ if (def_pager == MACH_PORT_NULL)
+ {
+ mach_port_t host;
+
+ err = get_privileged_ports (&host, &dev_master);
+ if (err)
+ error (12, err, "Cannot get host port");
+
+ err = vm_set_default_memory_manager (host, &def_pager);
+ mach_port_deallocate (mach_task_self (), host);
+ if (err)
+ error (13, err, "Cannot get default pager port");
+ if (def_pager == MACH_PORT_NULL)
+ error (14, 0, "No default pager (memory manager) is running!");
+ }
+
+ {
+ char pname[sizeof "/dev/" + strlen (store->name) + 1];
+ snprintf (pname, sizeof pname, "/dev/%s", store->name);
+ err = default_pager_paging_file (def_pager, dev_master, pname, add);
+ if (err)
+ error (0, err, "%s", file);
+ }
+
+ store_free (store);
+
+ return err;
+}
+
+static int do_all;
+
+int
+main(int argc, char *argv[])
+{
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'a':
+ do_all = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+#ifdef SWAPOFF
+#define ONOFF 0
+#else
+#define ONOFF 1
+#endif
+ swaponoff (arg, ONOFF);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (do_all)
+ {
+ struct mntent *me;
+ FILE *f;
+
+ f = setmntent (_PATH_MNTTAB, "r");
+ if (f == NULL)
+ error (1, errno, "Cannot read %s", _PATH_MNTTAB);
+ else
+ {
+ int done = 0, err = 0;
+ while ((me = getmntent (f)) != NULL)
+ if (!strcmp (me->mnt_type, MNTTYPE_SWAP))
+ {
+ done = 1;
+
+ err |= swaponoff (me->mnt_fsname, ONOFF);
+ }
+ if (done == 0)
+ error (2, 0, "No swap partitions found in %s", _PATH_MNTTAB);
+ else if (err)
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/sutils/update.c b/sutils/update.c
new file mode 100644
index 00000000..0342824f
--- /dev/null
+++ b/sutils/update.c
@@ -0,0 +1,54 @@
+/* Periodically call sync.
+ Copyright (C) 1994 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char **argv)
+{
+ int interval;
+
+ switch (argc)
+ {
+ case 1:
+ interval = 30;
+ break;
+ case 2:
+ interval = atoi (argv[1]);
+ break;
+ default:
+ fprintf (stderr, "Usage: %s [SECONDS]\n", argv[0]);
+ exit (1);
+ }
+
+ if (daemon (0, 0))
+ {
+ perror ("daemon");
+ exit (1);
+ }
+
+ for (;;)
+ {
+ sync ();
+ sleep (interval);
+ }
+}