r6255: Initial checkin of cifs umount utility
[kai/samba.git] / source / client / umount.cifs.c
1 /* 
2    Unmount utility program for Linux CIFS VFS (virtual filesystem) client
3    Copyright (C) 2005 Steve French  (sfrench@us.ibm.com)
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <ctype.h>
27 #include <sys/types.h>
28 #include <sys/mount.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <getopt.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <mntent.h>
36
37 #define UNMOUNT_CIFS_VERSION_MAJOR "0"
38 #define UNMOUNT_CIFS_VERSION_MINOR "1"
39
40 #ifndef UNMOUNT_CIFS_VENDOR_SUFFIX
41 #define UNMOUNT_CIFS_VENDOR_SUFFIX ""
42 #endif
43
44 #ifndef MNT_DETACH
45 #define MNT_DETACH 0x02
46 #endif
47
48 #ifndef MNT_EXPIRE
49 #define MNT_EXPIRE 0x04
50 #endif
51
52 #define CIFS_IOC_CHECKUMOUNT _IOR('u', 2, int)
53    
54 static struct option longopts[] = {
55         { "all", 0, NULL, 'a' },
56         { "help",0, NULL, 'h' },
57         { "read-only", 0, NULL, 'r' },
58         { "ro", 0, NULL, 'r' },
59         { "verbose", 0, NULL, 'v' },
60         { "version", 0, NULL, 'V' },
61         { "expire", 0, NULL, 'e' },
62         { "force", 0, 0, 'f' },
63         { "lazy", 0, 0, 'l' },
64         { "no-mtab", 0, 0, 'n' },
65         { NULL, 0, NULL, 0 }
66 };
67
68 char * thisprogram;
69 int verboseflg = 0;
70
71 static void umount_cifs_usage(void)
72 {
73         printf("\nUsage:  %s <remotetarget> <dir>\n", thisprogram);
74         printf("\nUnmount the specified directory\n");
75         printf("\nLess commonly used options:");
76         printf("\n\t-r\tIf mount fails, retry with readonly remount.");
77         printf("\n\t-n\tDo not write to mtab.");
78         printf("\n\t-f\tAttempt a forced unmount, even if the fs is busy.");
79         printf("\n\t-l\tAttempt lazy unmount, Unmount now, cleanup later.");
80         printf("\n\t-v\tEnable verbose mode (may be useful for debugging).");
81         printf("\n\t-h\tDisplay this help.");
82         printf("\n\nOptions are described in more detail in the manual page");
83         printf("\n\tman 8 umount.cifs\n");
84         printf("\nTo display the version number of the cifs umount utility:");
85         printf("\n\t%s -V\n",thisprogram);
86 }
87
88 static int umount_check_perm(char * dir)
89 {
90         int fileid;
91         int rc;
92
93         /* presumably can not chdir into the target as we do on mount */
94
95         fileid = open(dir, O_RDONLY | O_DIRECTORY | O_NOFOLLOW, 0);
96
97         /* check if fileid valid if fileid == -1 BB FIXME */
98
99         rc = ioctl(fileid, CIFS_IOC_CHECKUMOUNT, NULL);
100
101         if(verboseflg)
102                 printf("ioctl returned %d with errno %d\n",rc,errno);
103
104         close(fileid);
105
106         return rc;
107 }
108
109 int main(int argc, char ** argv)
110 {
111         int c;
112         int rc;
113         int flags = 0;
114         int nomtab = 0;
115         int retry_remount = 0;
116         struct mntent mountent;
117         char * mountpoint;
118         FILE * pmntfile;
119
120         if(argc && argv) {
121                 thisprogram = argv[0];
122         } else {
123                 umount_cifs_usage();
124                 return -EINVAL;
125         }
126
127         if(argc < 2) {
128                 umount_cifs_usage();
129                 return -EINVAL;
130         }
131
132         if(thisprogram == NULL)
133                 thisprogram = "umount.cifs";
134
135         /* add sharename in opts string as unc= parm */
136
137         while ((c = getopt_long (argc, argv, "afhilnrvV",
138                          longopts, NULL)) != -1) {
139                 switch (c) {
140 /* No code to do the following  option yet */
141 /*              case 'a':              
142                         ++umount_all;
143                         break; */
144                 case '?':
145                 case 'h':   /* help */
146                         umount_cifs_usage();
147                         exit(1);
148                 case 'n':
149                         ++nomtab;
150                         break;
151                 case 'f':
152                         flags |= MNT_FORCE;
153                         break;
154                 case 'l':
155                         flags |= MNT_DETACH; /* lazy unmount */
156                         break;
157                 case 'e':
158                         flags |= MNT_EXPIRE; /* gradually timeout */
159                         break;
160                 case 'r':
161                         ++retry_remount;
162                         break;
163                 case 'v':
164                         ++verboseflg;
165                         break;
166                 case 'V':          
167                         printf ("umount.cifs version: %s.%s%s\n",
168                                 UNMOUNT_CIFS_VERSION_MAJOR,
169                                 UNMOUNT_CIFS_VERSION_MINOR,
170                                 UNMOUNT_CIFS_VENDOR_SUFFIX);
171                         exit (0);
172                 default:
173                         printf("unknown unmount option %c\n",c);
174                         umount_cifs_usage();
175                         exit(1);
176                 }
177         }
178
179         /* move past the umount options */
180         argv += optind;
181         argc -= optind;
182
183         mountpoint = argv[0];
184
185         if((argc < 1) || (argv[0] == NULL)) {
186                 printf("\nMissing name of unmount directory\n");
187                 umount_cifs_usage();
188                 return -EINVAL;
189         }
190
191         if(verboseflg)
192                 printf("optind %d unmount dir %s\n",optind, mountpoint);
193
194         /* check if running effectively root */
195         if(geteuid() != 0)
196                 printf("Trying to unmount when %s not installed suid\n",thisprogram);
197
198         /* fixup path if needed */
199
200         /* check if our uid was the one who mounted */
201         rc = umount_check_perm(mountpoint);
202         if (rc) {
203                 return rc;
204         }
205
206         if(umount2(mountpoint, flags)) {
207         /* remember to kill daemon on error */
208
209                 switch (errno) {
210                 case 0:
211                         printf("mount failed but no error number set\n");
212                         break;
213                 default:
214                         
215                         printf("mount error %d = %s\n",errno,strerror(errno));
216                 }
217                 printf("Refer to the umount.cifs(8) manual page (e.g.man 8 umount.cifs)\n");
218                 return -1;
219         } else {
220                 pmntfile = setmntent(MOUNTED, "a+");
221                 if(pmntfile) {
222 /*                      mountent.mnt_fsname = share_name;
223                         mountent.mnt_dir = mountpoint; 
224                         mountent.mnt_type = "cifs"; 
225                         mountent.mnt_opts = malloc(220);
226                         if(mountent.mnt_opts) {
227                                 char * mount_user = getusername();
228                                 memset(mountent.mnt_opts,0,200);
229                                 if(flags & MS_RDONLY)
230                                         strcat(mountent.mnt_opts,"ro");
231                                 else
232                                         strcat(mountent.mnt_opts,"rw");
233                                 if(flags & MS_MANDLOCK)
234                                         strcat(mountent.mnt_opts,",mand");
235                                 else
236                                         strcat(mountent.mnt_opts,",nomand");
237                                 if(flags & MS_NOEXEC)
238                                         strcat(mountent.mnt_opts,",noexec");
239                                 if(flags & MS_NOSUID)
240                                         strcat(mountent.mnt_opts,",nosuid");
241                                 if(flags & MS_NODEV)
242                                         strcat(mountent.mnt_opts,",nodev");
243                                 if(flags & MS_SYNCHRONOUS)
244                                         strcat(mountent.mnt_opts,",synch");
245                                 if(mount_user) {
246                                         if(getuid() != 0) {
247                                                 strcat(mountent.mnt_opts,",user=");
248                                                 strcat(mountent.mnt_opts,mount_user);
249                                         }
250                                         free(mount_user);
251                                 }
252                         }
253                         mountent.mnt_freq = 0;
254                         mountent.mnt_passno = 0;
255                         rc = addmntent(pmntfile,&mountent);
256                         endmntent(pmntfile);
257                         if(mountent.mnt_opts)
258                                 free(mountent.mnt_opts);*/
259                 } else {
260                     printf("could not update mount table\n");
261                 }
262         }
263
264         return 0;
265 }
266