summaryrefslogtreecommitdiff
path: root/9umount.c
diff options
context:
space:
mode:
Diffstat (limited to '9umount.c')
-rw-r--r--9umount.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/9umount.c b/9umount.c
new file mode 100644
index 0000000..1adc9fe
--- /dev/null
+++ b/9umount.c
@@ -0,0 +1,140 @@
+/* © 2008 sqweek <sqweek@gmail.com>
+ * See COPYING for details.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <mntent.h>
+#include <pwd.h>
+
+char*
+canonpath(char *rel)
+{
+ char *abs, *cp, *prev;
+
+ if (rel[0] == '/') {
+ if (!(abs=malloc(strlen(rel) + 2))) {
+ return NULL;
+ }
+ abs[0] = '\0';
+ strcat(abs, rel);
+ strcat(abs, "/");
+ } else {
+ char *cwd = NULL;
+ if (!(cwd=getcwd(NULL, 0))) {
+ return NULL;
+ }
+ if (!(abs=malloc(strlen(cwd) + 1 + strlen(rel) + 2))) {
+ free(cwd);
+ return NULL;
+ }
+ abs[0] = '\0';
+ strcat(abs, cwd);
+ strcat(abs, "/");
+ strcat(abs, rel);
+ strcat(abs, "/");
+ free(cwd);
+ }
+
+ /* abs is now an absolute path which begins and ends with a slash */
+ prev = abs;
+ while ((cp=strchr(prev+1, '/'))) {
+ if (cp == prev+1) {
+ /* remove consecutive slashes */
+ memmove(prev, cp, strlen(cp)+1);
+ } else if (strncmp(prev, "/./", cp-prev+1) == 0) {
+ memmove(prev, cp, strlen(cp)+1);
+ } else if (strncmp(prev, "/../", cp-prev+1) == 0) {
+ char *parent;
+ if (prev == abs) {
+ parent = abs; /* just eat .. in root dir */
+ } else {
+ for (parent=prev-1; *parent != '/'; --parent);
+ }
+ memmove(parent, cp, strlen(cp)+1);
+ prev = parent;
+ } else {
+ prev = cp;
+ }
+ }
+ abs[strlen(abs)-1] = '\0'; /* remove trailing slash */
+
+ return abs;
+}
+
+int
+indir(struct mntent *mnt, char *dir)
+{
+ return (strncmp(mnt->mnt_dir, dir, strlen(dir)) == 0);
+}
+
+int
+mountedby(struct mntent *mnt, char *username)
+{
+ char *s, *cp;
+ if (!(s=strdup(mnt->mnt_opts))) {
+ errx(1, "out of memory");
+ }
+ for (cp=strtok(s, ","); cp; cp=strtok(NULL, ",")) {
+ if (strncmp(cp, "name=", 5) == 0) {
+ int eq = (strcmp(cp+5, username) == 0);
+ free(s);
+ return eq;
+ }
+ }
+ free(s);
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int ret = 0;
+ char *path;
+ FILE *fp;
+ struct mntent *mnt;
+ struct passwd *pw;
+
+ if (!(pw=getpwuid(getuid()))) {
+ err(1, "who are you?? getpwuid failed");
+ }
+
+ while (*++argv) {
+ if (!(path=canonpath(*argv))) {
+ warn("%s: canonpath", *argv);
+ continue;
+ }
+ if (!(fp=fopen("/proc/mounts", "r"))) {
+ err(1, "couldn't open /proc/mounts");
+ }
+ while ((mnt=getmntent(fp))) {
+ if (strcmp(path, mnt->mnt_dir) == 0) {
+ int inhomedir;
+ inhomedir = indir(mnt, pw->pw_dir);
+ if (!inhomedir && strcmp(mnt->mnt_type, "9p") != 0) {
+ warnx("%s: refusing to unmount non-9p fs", path);
+ ret = 1;
+ } else if (!inhomedir && !mountedby(mnt, pw->pw_name)) {
+ warnx("%s: not mounted by you", path);
+ ret = 1;
+ } else if (umount(mnt->mnt_dir)) {
+ warn("umount %s", mnt->mnt_dir);
+ ret = 1;
+ }
+ goto done;
+ }
+ }
+ warnx("%s not found in /proc/mounts", path);
+ ret = 1;
+
+done:
+ free(path);
+ fclose(fp);
+ }
+ return ret;
+}