aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2002-08-18 20:48:12 +0000
committerH. Peter Anvin <hpa@zytor.com>2002-08-18 20:48:12 +0000
commitb2c404ea503f5712a59c34ec6ae1e5acb781b28b (patch)
tree9528b83a6adcdc29367b5bf1619792f922368f22
parent1f72ddea76da0143e93f4e0fc794c6dac11603f2 (diff)
downloadklibc-b2c404ea503f5712a59c34ec6ae1e5acb781b28b.tar.gz
rmk: Patches for some old utilities.klibc-0.52
-rw-r--r--ash/Makefile4
-rw-r--r--ash/bltin/echo.c5
-rw-r--r--ash/mail.c115
-rw-r--r--ash/mail.h44
-rw-r--r--ash/main.c2
-rw-r--r--ash/var.c3
-rw-r--r--utils/Makefile13
-rw-r--r--utils/chroot.c26
-rw-r--r--utils/file_mode.c20
-rw-r--r--utils/mkdir.c38
-rw-r--r--utils/mkfifo.c2
-rw-r--r--utils/mount.c183
-rw-r--r--utils/pivot_root.c2
-rw-r--r--utils/umount.c45
14 files changed, 302 insertions, 200 deletions
diff --git a/ash/Makefile b/ash/Makefile
index 9187976bf98be..ca38182d49596 100644
--- a/ash/Makefile
+++ b/ash/Makefile
@@ -1,12 +1,12 @@
PROG= sh
SRCS= builtins.c cd.c dirent.c bltin/echo.c error.c eval.c exec.c expand.c \
- input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
+ input.c jobs.c main.c memalloc.c miscbltin.c \
mystring.c nodes.c options.c parser.c redir.c show.c \
syntax.c trap.c output.c var.c bltin/test.c
OBJ1 = init.o
OBJ2 = builtins.o cd.o dirent.o bltin/echo.o error.o eval.o exec.o expand.o \
- input.o jobs.o mail.o main.o memalloc.o miscbltin.o \
+ input.o jobs.o main.o memalloc.o miscbltin.o \
mystring.o nodes.o options.o parser.o redir.o show.o \
syntax.o trap.o output.o var.o bltin/test.o
diff --git a/ash/bltin/echo.c b/ash/bltin/echo.c
index cd2e072ac29d0..82d1ffa8266c7 100644
--- a/ash/bltin/echo.c
+++ b/ash/bltin/echo.c
@@ -66,7 +66,10 @@ main(argc, argv) char **argv; {
if (equal(p, "-n")) {
nflag++;
ap++;
- } else if (equal(p, "-e")) {
+ }
+ }
+ if ((p = *ap) != NULL) {
+ if (equal(p, "-e")) {
#ifndef eflag
eflag++;
#endif
diff --git a/ash/mail.c b/ash/mail.c
deleted file mode 100644
index 18d151ff632e3..0000000000000
--- a/ash/mail.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-/*static char sccsid[] = "from: @(#)mail.c 5.1 (Berkeley) 3/7/91";*/
-static char rcsid[] = "mail.c,v 1.4 1993/08/01 18:58:13 mycroft Exp";
-#endif /* not lint */
-
-/*
- * Routines to check for mail. (Perhaps make part of main.c?)
- */
-
-#include "shell.h"
-#include "exec.h" /* defines padvance() */
-#include "var.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
-
-#define MAXMBOXES 10
-
-
-STATIC int nmboxes; /* number of mailboxes */
-STATIC time_t mailtime[MAXMBOXES]; /* times of mailboxes */
-
-
-
-/*
- * Print appropriate message(s) if mail has arrived. If the argument is
- * nozero, then the value of MAIL has changed, so we just update the
- * values.
- */
-
-void
-chkmail(silent) {
- register int i;
- char *mpath;
- char *p;
- register char *q;
- struct stackmark smark;
- struct stat statb;
-
- if (silent)
- nmboxes = 10;
- if (nmboxes == 0)
- return;
- setstackmark(&smark);
- mpath = mpathset()? mpathval() : mailval();
- for (i = 0 ; i < nmboxes ; i++) {
- p = padvance(&mpath, nullstr);
- if (p == NULL)
- break;
- if (*p == '\0')
- continue;
- for (q = p ; *q ; q++);
- if (q[-1] != '/')
- abort();
- q[-1] = '\0'; /* delete trailing '/' */
-#ifdef notdef /* this is what the System V shell claims to do (it lies) */
- if (stat(p, &statb) < 0)
- statb.st_mtime = 0;
- if (statb.st_mtime > mailtime[i] && ! silent) {
- out2str(pathopt? pathopt : "you have mail");
- out2c('\n');
- }
- mailtime[i] = statb.st_mtime;
-#else /* this is what it should do */
- if (stat(p, &statb) < 0)
- statb.st_size = 0;
- if (statb.st_size > mailtime[i] && ! silent) {
- out2str(pathopt? pathopt : "you have mail");
- out2c('\n');
- }
- mailtime[i] = statb.st_size;
-#endif
- }
- nmboxes = i;
- popstackmark(&smark);
-}
diff --git a/ash/mail.h b/ash/mail.h
deleted file mode 100644
index 64efe4e2bfb41..0000000000000
--- a/ash/mail.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)mail.h 5.1 (Berkeley) 3/7/91
- * mail.h,v 1.4 1993/08/01 18:58:25 mycroft Exp
- */
-
-#ifdef __STDC__
-void chkmail(int);
-#else
-void chkmail();
-#endif
diff --git a/ash/main.c b/ash/main.c
index 8b3b5b0789b77..710a810ea98b1 100644
--- a/ash/main.c
+++ b/ash/main.c
@@ -49,7 +49,6 @@ static char rcsid[] = "main.c,v 1.4 1993/08/01 18:58:12 mycroft Exp";
#include <fcntl.h>
#include "shell.h"
#include "main.h"
-#include "mail.h"
#include "options.h"
#include "output.h"
#include "parser.h"
@@ -198,7 +197,6 @@ cmdloop(top) {
if (iflag && top) {
inter++;
showjobs(1);
- chkmail(0);
flushout(&output);
}
n = parsecmd(inter);
diff --git a/ash/var.c b/ash/var.c
index 34f99639000e9..653d820271d7e 100644
--- a/ash/var.c
+++ b/ash/var.c
@@ -51,7 +51,6 @@ static char rcsid[] = "var.c,v 1.4 1993/08/01 18:57:58 mycroft Exp";
#include "exec.h"
#include "syntax.h"
#include "options.h"
-#include "mail.h"
#include "var.h"
#include "memalloc.h"
#include "error.h"
@@ -236,8 +235,6 @@ setvareq(s, flags)
vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
vp->flags |= flags;
vp->text = s;
- if (iflag && (vp == &vmpath || (vp == &vmail && ! mpathset())))
- chkmail(1);
INTON;
return;
}
diff --git a/utils/Makefile b/utils/Makefile
index 3f8eff39a7cf0..82525eb524e1e 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -2,21 +2,30 @@ KLIBSRC = ../klibc
include ../MCONFIG
-CFLAGS = $(OPTFLAGS) $(REQFLAGS)
+CFLAGS = $(OPTFLAGS) $(REQFLAGS) -W -Wall
LIBS = $(KLIBC) $(LIBGCC)
-PROGS = mkdir mkfifo pivot_root
+PROGS = chroot mkdir mkfifo mount pivot_root umount
all: $(PROGS)
+chroot: chroot.o $(CRT0) $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $(CRT0) chroot.o $(LIBS)
+
mkdir: mkdir.o file_mode.o $(CRT0) $(LIBS)
$(LD) $(LDFLAGS) -o $@ $(CRT0) mkdir.o file_mode.o $(LIBS)
mkfifo: mkfifo.o file_mode.o $(CRT0) $(LIBS)
$(LD) $(LDFLAGS) -o $@ $(CRT0) mkfifo.o file_mode.o $(LIBS)
+mount: mount.o $(CRT0) $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $(CRT0) mount.o $(LIBS)
+
pivot_root: pivot_root.o $(CRT0) $(LIBS)
$(LD) $(LDFLAGS) -o $@ $(CRT0) pivot_root.o $(LIBS)
+umount: umount.o $(CRT0) $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $(CRT0) umount.o $(LIBS)
+
$(CRT0) $(LIBS):
@echo '*** error: $@ not up to date' || exit 1
diff --git a/utils/chroot.c b/utils/chroot.c
new file mode 100644
index 0000000000000..728539ca0fb05
--- /dev/null
+++ b/utils/chroot.c
@@ -0,0 +1,26 @@
+/*
+ * chroot.c, by rmk
+ */
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s newroot command...\n",
+ argv[0]);
+ return 1;
+ }
+
+ if (chroot(argv[1]) == -1) {
+ perror("chroot");
+ return 1;
+ }
+
+ if (execve(argv[2], argv + 2, envp) == -1) {
+ perror("execve");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/utils/file_mode.c b/utils/file_mode.c
index dc0f3e9da97d2..24d69f86c053b 100644
--- a/utils/file_mode.c
+++ b/utils/file_mode.c
@@ -34,24 +34,22 @@ mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask)
* Parse the who list. Optional.
*/
while (1) {
- switch (*p) {
+ switch (*p++) {
case 'u':
who |= S_IRWXU | S_ISUID;
- p++;
continue;
case 'g':
who |= S_IRWXG | S_ISGID;
- p++;
continue;
case 'o':
- p++;
who |= S_IRWXO | S_ISVTX;
continue;
case 'a':
- p++;
who = S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX;
continue;
}
+ /* undo the increment above */
+ p--;
break;
}
@@ -75,47 +73,41 @@ mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask)
* Parse perm
*/
while (*p) {
- switch (*p) {
+ switch (*p++) {
case 'r':
perm |= S_IRUSR|S_IRGRP|S_IROTH;
- *p++;
continue;
case 'w':
perm |= S_IWUSR|S_IWGRP|S_IWOTH;
- *p++;
continue;
case 'x':
perm |= S_IXUSR|S_IXGRP|S_IXOTH;
- *p++;
continue;
case 'X':
perm |= S_ISVTX;
- *p++;
continue;
case 's':
perm |= S_ISUID|S_ISGID;
- *p++;
continue;
case 'u':
perm = mode & S_IRWXU;
perm |= perm >> 3 | perm >> 6;
if (mode & S_ISUID)
perm |= S_ISGID;
- *p++;
continue;
case 'g':
perm = mode & S_IRWXG;
perm |= perm << 3 | perm >> 3;
if (mode & S_ISGID)
perm |= S_ISUID;
- *p++;
continue;
case 'o':
perm = mode & S_IRWXO;
perm |= perm << 6 | perm << 3;
- *p++;
continue;
}
+ /* undo the increment above */
+ p--;
break;
}
diff --git a/utils/mkdir.c b/utils/mkdir.c
index c6f56566b2e3d..83b8fec8e083b 100644
--- a/utils/mkdir.c
+++ b/utils/mkdir.c
@@ -32,7 +32,7 @@ static int make_one_dir(char *dir, mode_t mode)
if (p_flag && errno == EEXIST &&
stat(dir, &stbuf) == 0 &&
S_ISDIR(stbuf.st_mode))
- return 0;
+ return 1;
errno = err;
fprintf(stderr, "%s: ", progname);
perror(dir);
@@ -43,6 +43,8 @@ static int make_one_dir(char *dir, mode_t mode)
static int make_dir(char *dir)
{
+ int ret;
+
if (p_flag) {
char *s, *p;
@@ -54,17 +56,22 @@ static int make_dir(char *dir)
*/
s = dir;
while ((p = strchr(s, '/')) != NULL) {
- *p = '\0';
-
/*
- * Make the intermediary directory. POSIX
- * says that these directories are created
- * with umask,u+wx
+ * Ignore the leading /
*/
- if (make_one_dir(dir, subdir_mode) == -1)
- return -1;
-
- *p = '/';
+ if (p != dir) {
+ *p = '\0';
+
+ /*
+ * Make the intermediary directory. POSIX
+ * says that these directories are created
+ * with umask,u+wx
+ */
+ if (make_one_dir(dir, subdir_mode) == -1)
+ return -1;
+
+ *p = '/';
+ }
s = p + 1;
}
}
@@ -74,18 +81,19 @@ static int make_dir(char *dir)
* target already exists if -p was not specified.
* This is created with the asked for mode & ~umask
*/
- if (make_one_dir(dir, leaf_mode))
+ ret = make_one_dir(dir, leaf_mode);
+ if (ret == -1)
return -1;
/*
* We might not set all the permission bits. Do that
- * here.
+ * here (but only if we did create it.)
*/
- if (chmod(dir, leaf_mode) == -1) {
+ if (ret == 0 && chmod(dir, leaf_mode) == -1) {
int err_save = errno;
/*
- * We failed, remove the directory we created.
+ * We failed, remove the directory we created
*/
rmdir(dir);
errno = err_save;
@@ -98,7 +106,7 @@ static int make_dir(char *dir)
int main(int argc, char *argv[])
{
- int c, ret;
+ int c, ret = 0;
mode_t saved_umask;
progname = argv[0];
diff --git a/utils/mkfifo.c b/utils/mkfifo.c
index 5775b802b57fa..e48032b5e5b2d 100644
--- a/utils/mkfifo.c
+++ b/utils/mkfifo.c
@@ -29,7 +29,7 @@ static int make_fifo(char *dir)
int main(int argc, char *argv[])
{
- int c, ret;
+ int c, ret = 0;
mode_t saved_umask;
progname = argv[0];
diff --git a/utils/mount.c b/utils/mount.c
new file mode 100644
index 0000000000000..85a1758273737
--- /dev/null
+++ b/utils/mount.c
@@ -0,0 +1,183 @@
+/*
+ * mount.c, by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *progname;
+
+struct mount_opts {
+ const char str[8];
+ unsigned long rwmask;
+ unsigned long rwset;
+ unsigned long rwnoset;
+};
+
+struct extra_opts {
+ char *str;
+ char *end;
+ int used_size;
+ int alloc_size;
+};
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define MS_SYNC MS_SYNCHRONOUS
+
+#ifndef MS_MOVE /* please add */
+#define MS_MOVE 8192
+#endif
+
+#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
+
+static const struct mount_opts options[] = {
+ { "async", MS_SYNC, 0, MS_SYNC },
+ { "atime", MS_NOATIME, 0, MS_NOATIME },
+ { "bind", MS_TYPE, MS_BIND, 0, },
+ { "dev", MS_NODEV, 0, MS_NODEV },
+ { "diratime", MS_NODIRATIME, 0, MS_NODIRATIME },
+ { "exec", MS_NOEXEC, 0, MS_NOEXEC },
+ { "move", MS_TYPE, MS_MOVE, 0 },
+ { "recurse", MS_REC, MS_REC, 0 },
+ { "remount", MS_TYPE, MS_REMOUNT, 0 },
+ { "ro", MS_RDONLY, MS_RDONLY, 0 },
+ { "rw", MS_RDONLY, 0, MS_RDONLY },
+ { "suid", MS_NOSUID, 0, MS_NOSUID },
+ { "sync", MS_SYNC, MS_SYNC, 0 },
+ { "verbose", MS_VERBOSE, MS_VERBOSE, 0 },
+};
+
+static struct extra_opts extra;
+static unsigned long rwflag;
+
+static void add_extra_option(char *s)
+{
+ int len = strlen(s) + 1; /* +1 for ',' */
+ int newlen = extra.used_size + len;
+
+ if (newlen >= extra.alloc_size) {
+ char *new;
+
+ new = realloc(extra.str, newlen + 1); /* +1 for NUL */
+ if (!new)
+ return;
+
+ extra.end += new - extra.str;
+ extra.str = new;
+ extra.alloc_size = newlen;
+ }
+
+ if (extra.used_size)
+ *extra.end = ',';
+ strcpy(extra.end, s);
+ extra.used_size += len;
+}
+
+static unsigned long parse_mount_options(char *arg, unsigned long rwflag)
+{
+ char *s;
+
+ while ((s = strsep(&arg, ",")) != NULL) {
+ char *opt = s;
+ unsigned int i;
+ int res, no = s[0] == 'n' && s[1] == 'o';
+
+ if (no)
+ s += 2;
+
+ for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
+ res = strcmp(s, options[i].str);
+
+ if (res == 0) {
+ rwflag &= ~options[i].rwmask;
+ if (no)
+ rwflag |= options[i].rwnoset;
+ else
+ rwflag |= options[i].rwset;
+ }
+ if (res >= 0)
+ break;
+ }
+
+ if (res != 0 && s[0])
+ add_extra_option(opt);
+ }
+
+ return rwflag;
+}
+
+static int
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data)
+{
+ char *s;
+ int error = 0;
+
+ while ((s = strsep(&type, ",")) != NULL) {
+ if (mount(dev, dir, s, rwflag, data) == -1) {
+ error = errno;
+ if (error == ENODEV)
+ continue;
+ }
+ }
+
+ if (error) {
+ errno = error;
+ perror("mount");
+ return 255;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char *type = NULL;
+ int c;
+
+ progname = argv[0];
+ rwflag = MS_VERBOSE;
+
+ do {
+ c = getopt(argc, argv, "o:rt:w");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'o':
+ rwflag = parse_mount_options(optarg, rwflag);
+ break;
+ case 'r':
+ rwflag |= MS_RDONLY;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'w':
+ rwflag &= ~MS_RDONLY;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ /*
+ * If remount, bind or move was specified, then we don't
+ * have a "type" as such. Use the dummy "none" type.
+ */
+ if (rwflag & MS_TYPE)
+ type = "none";
+
+ if (optind + 2 != argc || type == NULL) {
+ fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] "
+ "device directory\n", progname);
+ exit(1);
+ }
+
+ return do_mount(argv[optind], argv[optind + 1], type, rwflag,
+ extra.str);
+}
diff --git a/utils/pivot_root.c b/utils/pivot_root.c
index 0da2d902f826d..75a1eeceb34ec 100644
--- a/utils/pivot_root.c
+++ b/utils/pivot_root.c
@@ -3,7 +3,7 @@
/* Written 2000 by Werner Almesberger */
#include <stdio.h>
-#include <unistd.h>
+#include <sys/mount.h>
int main(int argc,const char **argv)
{
diff --git a/utils/umount.c b/utils/umount.c
new file mode 100644
index 0000000000000..5628916ca711a
--- /dev/null
+++ b/utils/umount.c
@@ -0,0 +1,45 @@
+/*
+ * umount.c, by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *progname;
+
+int main(int argc, char *argv[])
+{
+ int c, flag = 0;
+
+ progname = argv[0];
+
+ do {
+ c = getopt(argc, argv, "f");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ flag |= MNT_FORCE;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "Usage: %s [-f] mntpoint\n", progname);
+ return 1;
+ }
+
+ if (umount2(argv[optind], flag) == -1) {
+ perror("umount2");
+ return 255;
+ }
+
+ return 0;
+}