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 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#include <sys/mount.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <sys/vfs.h>
#include <fcntl.h>
#include <getopt.h>
#include <errno.h>
#include <mntent.h>
#define UNMOUNT_CIFS_VERSION_MAJOR "0"
-#define UNMOUNT_CIFS_VERSION_MINOR "1"
+#define UNMOUNT_CIFS_VERSION_MINOR "5"
#ifndef UNMOUNT_CIFS_VENDOR_SUFFIX
-#define UNMOUNT_CIFS_VENDOR_SUFFIX ""
-#endif
+ #ifdef _SAMBA_BUILD_
+ #include "include/version.h"
+ #ifdef SAMBA_VERSION_VENDOR_SUFFIX
+ #define UNMOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
+ #else
+ #define UNMOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
+ #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
+ #else
+ #define UNMOUNT_CIFS_VENDOR_SUFFIX ""
+ #endif /* _SAMBA_BUILD_ */
+#endif /* UNMOUNT_CIFS_VENDOR_SUFFIX */
#ifndef MNT_DETACH
#define MNT_DETACH 0x02
#define MNT_EXPIRE 0x04
#endif
-#define CIFS_IOC_CHECKUMOUNT _IO('c', 2)
+#ifndef MOUNTED_LOCK
+#define MOUNTED_LOCK "/etc/mtab~"
+#endif
+#ifndef MOUNTED_TEMP
+#define MOUNTED_TEMP "/etc/mtab.tmp"
+#endif
+
+#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
+#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDU */
static struct option longopts[] = {
{ "all", 0, NULL, 'a' },
{ NULL, 0, NULL, 0 }
};
-char * thisprogram;
+const char * thisprogram;
int verboseflg = 0;
static void umount_cifs_usage(void)
printf("\n\tman 8 umount.cifs\n");
printf("\nTo display the version number of the cifs umount utility:");
printf("\n\t%s -V\n",thisprogram);
+ printf("\nInvoking the umount utility on cifs mounts, can execute");
+ printf(" /sbin/umount.cifs (if present and umount -i is not specified.\n");
}
static int umount_check_perm(char * dir)
int fileid;
int rc;
- /* presumably can not chdir into the target as we do on mount */
+ /* allow root to unmount, no matter what */
+ if(getuid() == 0)
+ return 0;
+ /* presumably can not chdir into the target as we do on mount */
fileid = open(dir, O_RDONLY | O_DIRECTORY | O_NOFOLLOW, 0);
if(fileid == -1) {
if(verboseflg)
if(verboseflg)
printf("ioctl returned %d with errno %d %s\n",rc,errno,strerror(errno));
- if(rc == ENOTTY)
- printf("user unmounting via %s is an optional feature of the cifs filesystem driver (cifs.ko)\n\tand requires cifs.ko version 1.32 or later\n",thisprogram);
- else if (rc > 0)
- printf("user unmount of %s failed with %d %s",dir,errno,strerror(errno));
+ if(rc == ENOTTY) {
+ printf("user unmounting via %s is an optional feature of",thisprogram);
+ printf(" the cifs filesystem driver (cifs.ko)");
+ printf("\n\tand requires cifs.ko version 1.32 or later\n");
+ } else if (rc > 0)
+ printf("user unmount of %s failed with %d %s\n",dir,errno,strerror(errno));
close(fileid);
return rc;
}
+static int lock_mtab(void)
+{
+ int rc;
+
+ rc = mknod(MOUNTED_LOCK , 0600, 0);
+ if(rc == -1)
+ printf("\ngetting lock file %s failed with %s\n",MOUNTED_LOCK,
+ strerror(errno));
+
+ return rc;
+
+}
+
+static void unlock_mtab(void)
+{
+ unlink(MOUNTED_LOCK);
+}
+
+static int remove_from_mtab(char * mountpoint)
+{
+ int rc;
+ int num_matches;
+ FILE * org_fd;
+ FILE * new_fd;
+ struct mntent * mount_entry;
+
+ /* Do we need to check if it is a symlink to e.g. /proc/mounts
+ in which case we probably do not want to update it? */
+
+ /* Do we first need to check if it is writable? */
+
+ if (lock_mtab()) {
+ printf("Mount table locked\n");
+ return -EACCES;
+ }
+
+ if(verboseflg)
+ printf("attempting to remove from mtab\n");
+
+ org_fd = setmntent(MOUNTED, "r");
+
+ if(org_fd == NULL) {
+ printf("Can not open %s\n",MOUNTED);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ new_fd = setmntent(MOUNTED_TEMP,"w");
+ if(new_fd == NULL) {
+ printf("Can not open temp file %s", MOUNTED_TEMP);
+ endmntent(org_fd);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ /* BB fix so we only remove the last entry that matches BB */
+ num_matches = 0;
+ while((mount_entry = getmntent(org_fd)) != NULL) {
+ if(strcmp(mount_entry->mnt_dir, mountpoint) == 0) {
+ num_matches++;
+ }
+ }
+ if(verboseflg)
+ printf("%d matching entries in mount table\n", num_matches);
+
+ /* Is there a better way to seek back to the first entry in mtab? */
+ endmntent(org_fd);
+ org_fd = setmntent(MOUNTED, "r");
+
+ if(org_fd == NULL) {
+ printf("Can not open %s\n",MOUNTED);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ while((mount_entry = getmntent(org_fd)) != NULL) {
+ if(strcmp(mount_entry->mnt_dir, mountpoint) != 0) {
+ addmntent(new_fd, mount_entry);
+ } else {
+ if(num_matches != 1) {
+ addmntent(new_fd, mount_entry);
+ num_matches--;
+ } else if(verboseflg)
+ printf("entry not copied (ie entry is removed)\n");
+ }
+ }
+
+ if(verboseflg)
+ printf("done updating tmp file\n");
+ rc = fchmod (fileno (new_fd), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if(rc < 0) {
+ printf("error %s changing mode of %s\n", strerror(errno),
+ MOUNTED_TEMP);
+ }
+ endmntent(new_fd);
+
+ rc = rename(MOUNTED_TEMP, MOUNTED);
+
+ if(rc < 0) {
+ printf("failure %s renaming %s to %s\n",strerror(errno),
+ MOUNTED_TEMP, MOUNTED);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ unlock_mtab();
+
+ return rc;
+}
+
int main(int argc, char ** argv)
{
int c;
int flags = 0;
int nomtab = 0;
int retry_remount = 0;
- struct mntent mountent;
+ struct statfs statbuf;
char * mountpoint;
- FILE * pmntfile;
if(argc && argv) {
thisprogram = argv[0];
printf("optind %d unmount dir %s\n",optind, mountpoint);
/* check if running effectively root */
- if(geteuid() != 0)
+ if(geteuid() != 0) {
printf("Trying to unmount when %s not installed suid\n",thisprogram);
+ if(verboseflg)
+ printf("euid = %d\n",geteuid());
+ return -EACCES;
+ }
/* fixup path if needed */
+ /* Trim any trailing slashes */
+ while ((strlen(mountpoint) > 1) &&
+ (mountpoint[strlen(mountpoint)-1] == '/'))
+ {
+ mountpoint[strlen(mountpoint)-1] = '\0';
+ }
+
+ /* make sure that this is a cifs filesystem */
+ rc = statfs(mountpoint, &statbuf);
+
+ if(rc || (statbuf.f_type != CIFS_MAGIC_NUMBER)) {
+ printf("This utility only unmounts cifs filesystems.\n");
+ return -EINVAL;
+ }
+
/* check if our uid was the one who mounted */
rc = umount_check_perm(mountpoint);
if (rc) {
+ printf("Not permitted to unmount\n");
return rc;
}
if(umount2(mountpoint, flags)) {
/* remember to kill daemon on error */
-
switch (errno) {
case 0:
- printf("mount failed but no error number set\n");
+ printf("unmount failed but no error number set\n");
break;
default:
-
- printf("mount error %d = %s\n",errno,strerror(errno));
+ printf("unmount error %d = %s\n",errno,strerror(errno));
}
- printf("Refer to the umount.cifs(8) manual page (e.g.man 8 umount.cifs)\n");
+ printf("Refer to the umount.cifs(8) manual page (man 8 umount.cifs)\n");
return -1;
} else {
- pmntfile = setmntent(MOUNTED, "a+");
- if(pmntfile) {
-/* mountent.mnt_fsname = share_name;
- mountent.mnt_dir = mountpoint;
- mountent.mnt_type = "cifs";
- mountent.mnt_opts = malloc(220);
- if(mountent.mnt_opts) {
- char * mount_user = getusername();
- memset(mountent.mnt_opts,0,200);
- if(flags & MS_RDONLY)
- strcat(mountent.mnt_opts,"ro");
- else
- strcat(mountent.mnt_opts,"rw");
- if(flags & MS_MANDLOCK)
- strcat(mountent.mnt_opts,",mand");
- else
- strcat(mountent.mnt_opts,",nomand");
- if(flags & MS_NOEXEC)
- strcat(mountent.mnt_opts,",noexec");
- if(flags & MS_NOSUID)
- strcat(mountent.mnt_opts,",nosuid");
- if(flags & MS_NODEV)
- strcat(mountent.mnt_opts,",nodev");
- if(flags & MS_SYNCHRONOUS)
- strcat(mountent.mnt_opts,",synch");
- if(mount_user) {
- if(getuid() != 0) {
- strcat(mountent.mnt_opts,",user=");
- strcat(mountent.mnt_opts,mount_user);
- }
- free(mount_user);
- }
- }
- mountent.mnt_freq = 0;
- mountent.mnt_passno = 0;
- rc = addmntent(pmntfile,&mountent);
- endmntent(pmntfile);
- if(mountent.mnt_opts)
- free(mountent.mnt_opts);*/
- } else {
- printf("could not update mount table\n");
- }
+ if(verboseflg)
+ printf("umount2 succeeded\n");
+ if(nomtab == 0)
+ remove_from_mtab(mountpoint);
}
return 0;