154 lines · 3.1 KB · C
RawDownload
/* © 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 <sys/wait.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;} intindir(struct mntent *mnt, char *dir){	return (strncmp(mnt->mnt_dir, dir, strlen(dir)) == 0);} intmountedby(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;} intmain(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 {					int pid, status;					switch(pid=fork()) {						case -1:							warn("%s: fork", path);						case 0:							setuid(0);							execl("/bin/umount", "umount", mnt->mnt_dir, (char*)NULL);							warn("%s: execl", path);						default:							wait(&status);							if(WEXITSTATUS(status) != 0) {								warn("%s: couldn't unmount", path);								ret = 1;							}					}				}				goto done;			}		}		warnx("%s not found in /proc/mounts", path);		ret = 1; done:		free(path);		fclose(fp);	}	return ret;}