1 /*-
2 * Copyright (c) 1980, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1989, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 05/08/95";
16 #endif /* not lint */
17
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <sys/mount.h>
21 #include <sys/time.h>
22 #include <sys/socket.h>
23 #include <sys/socketvar.h>
24
25 #include <netdb.h>
26 #include <rpc/rpc.h>
27 #include <rpc/pmap_clnt.h>
28 #include <rpc/pmap_prot.h>
29 #include <nfs/rpcv2.h>
30
31 #include <err.h>
32 #include <fstab.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 typedef enum { MNTON, MNTFROM } mntwhat;
39
40 int fake, fflag, vflag;
41 char *nfshost;
42
43 int checkvfsname __P((const char *, char **));
44 char *getmntname __P((char *, mntwhat, char **));
45 char **makevfslist __P((char *));
46 int selected __P((int));
47 int namematch __P((struct hostent *));
48 int umountall __P((char **));
49 int umountfs __P((char *, char **));
50 void usage __P((void));
51 int xdr_dir __P((XDR *, char *));
52
53 int
main(argc,argv)54 main(argc, argv)
55 int argc;
56 char *argv[];
57 {
58 int all, ch, errs, mnts;
59 char **typelist = NULL;
60 struct statfs *mntbuf;
61
62 /* Start disks transferring immediately. */
63 sync();
64
65 all = 0;
66 while ((ch = getopt(argc, argv, "AaFfh:t:v")) != EOF)
67 switch (ch) {
68 case 'A':
69 all = 2;
70 break;
71 case 'a':
72 all = 1;
73 break;
74 case 'F':
75 fake = 1;
76 break;
77 case 'f':
78 fflag = MNT_FORCE;
79 break;
80 case 'h': /* -h implies -A. */
81 all = 2;
82 nfshost = optarg;
83 break;
84 case 't':
85 if (typelist != NULL)
86 errx(1, "only one -t option may be specified.");
87 typelist = makevfslist(optarg);
88 break;
89 case 'v':
90 vflag = 1;
91 break;
92 default:
93 usage();
94 /* NOTREACHED */
95 }
96 argc -= optind;
97 argv += optind;
98
99 if (argc == 0 && !all || argc != 0 && all)
100 usage();
101
102 /* -h implies "-t nfs" if no -t flag. */
103 if ((nfshost != NULL) && (typelist == NULL))
104 typelist = makevfslist("nfs");
105
106 switch (all) {
107 case 2:
108 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
109 warn("getmntinfo");
110 errs = 1;
111 break;
112 }
113 for (errs = 0, mnts--; mnts > 0; mnts--) {
114 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
115 continue;
116 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
117 errs = 1;
118 }
119 break;
120 case 1:
121 if (setfsent() == 0)
122 err(1, "%s", _PATH_FSTAB);
123 errs = umountall(typelist);
124 break;
125 case 0:
126 for (errs = 0; *argv != NULL; ++argv)
127 if (umountfs(*argv, typelist) != 0)
128 errs = 1;
129 break;
130 }
131 exit(errs);
132 }
133
134 int
umountall(typelist)135 umountall(typelist)
136 char **typelist;
137 {
138 struct fstab *fs;
139 int rval, type;
140 char *cp;
141 struct vfsconf vfc;
142
143 while ((fs = getfsent()) != NULL) {
144 /* Ignore the root. */
145 if (strcmp(fs->fs_file, "/") == 0)
146 continue;
147 /*
148 * !!!
149 * Historic practice: ignore unknown FSTAB_* fields.
150 */
151 if (strcmp(fs->fs_type, FSTAB_RW) &&
152 strcmp(fs->fs_type, FSTAB_RO) &&
153 strcmp(fs->fs_type, FSTAB_RQ))
154 continue;
155 /* If an unknown file system type, complain. */
156 if (getvfsbyname(fs->fs_vfstype, &vfc) < 0) {
157 warnx("%s: unknown mount type", fs->fs_vfstype);
158 continue;
159 }
160 if (checkvfsname(fs->fs_vfstype, typelist))
161 continue;
162
163 /*
164 * We want to unmount the file systems in the reverse order
165 * that they were mounted. So, we save off the file name
166 * in some allocated memory, and then call recursively.
167 */
168 if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
169 err(1, NULL);
170 (void)strcpy(cp, fs->fs_file);
171 rval = umountall(typelist);
172 return (umountfs(cp, typelist) || rval);
173 }
174 return (0);
175 }
176
177 int
umountfs(name,typelist)178 umountfs(name, typelist)
179 char *name;
180 char **typelist;
181 {
182 enum clnt_stat clnt_stat;
183 struct hostent *hp;
184 struct sockaddr_in saddr;
185 struct stat sb;
186 struct timeval pertry, try;
187 CLIENT *clp;
188 int so;
189 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
190
191 if (realpath(name, rname) == NULL) {
192 warn("%s", rname);
193 return (1);
194 }
195
196 name = rname;
197
198 if (stat(name, &sb) < 0) {
199 if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) &&
200 ((mntpt = getmntname(name, MNTON, &type)) == NULL)) {
201 warnx("%s: not currently mounted", name);
202 return (1);
203 }
204 } else if (S_ISBLK(sb.st_mode)) {
205 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
206 warnx("%s: not currently mounted", name);
207 return (1);
208 }
209 } else if (S_ISDIR(sb.st_mode)) {
210 mntpt = name;
211 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
212 warnx("%s: not currently mounted", mntpt);
213 return (1);
214 }
215 } else {
216 warnx("%s: not a directory or special device", name);
217 return (1);
218 }
219
220 if (checkvfsname(type, typelist))
221 return (1);
222
223 hp = NULL;
224 if (!strcmp(type, "nfs")) {
225 if ((delimp = strchr(name, '@')) != NULL) {
226 hostp = delimp + 1;
227 *delimp = '\0';
228 hp = gethostbyname(hostp);
229 *delimp = '@';
230 } else if ((delimp = strchr(name, ':')) != NULL) {
231 *delimp = '\0';
232 hostp = name;
233 hp = gethostbyname(hostp);
234 name = delimp + 1;
235 *delimp = ':';
236 }
237 }
238
239 if (!namematch(hp))
240 return (1);
241
242 if (vflag)
243 (void)printf("%s: unmount from %s\n", name, mntpt);
244 if (fake)
245 return (0);
246
247 if (unmount(mntpt, fflag) < 0) {
248 warn("%s", mntpt);
249 return (1);
250 }
251
252 if ((hp != NULL) && !(fflag & MNT_FORCE)) {
253 *delimp = '\0';
254 memset(&saddr, 0, sizeof(saddr));
255 saddr.sin_family = AF_INET;
256 saddr.sin_port = 0;
257 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
258 pertry.tv_sec = 3;
259 pertry.tv_usec = 0;
260 so = RPC_ANYSOCK;
261 if ((clp = clntudp_create(&saddr,
262 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
263 clnt_pcreateerror("Cannot MNT PRC");
264 return (1);
265 }
266 clp->cl_auth = authunix_create_default();
267 try.tv_sec = 20;
268 try.tv_usec = 0;
269 clnt_stat = clnt_call(clp,
270 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
271 if (clnt_stat != RPC_SUCCESS) {
272 clnt_perror(clp, "Bad MNT RPC");
273 return (1);
274 }
275 auth_destroy(clp->cl_auth);
276 clnt_destroy(clp);
277 }
278 return (0);
279 }
280
281 char *
getmntname(name,what,type)282 getmntname(name, what, type)
283 char *name;
284 mntwhat what;
285 char **type;
286 {
287 static struct statfs *mntbuf;
288 static int mntsize;
289 int i;
290
291 if (mntbuf == NULL &&
292 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
293 warn("getmntinfo");
294 return (NULL);
295 }
296 for (i = 0; i < mntsize; i++) {
297 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
298 if (type)
299 *type = mntbuf[i].f_fstypename;
300 return (mntbuf[i].f_mntonname);
301 }
302 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
303 if (type)
304 *type = mntbuf[i].f_fstypename;
305 return (mntbuf[i].f_mntfromname);
306 }
307 }
308 return (NULL);
309 }
310
311 int
namematch(hp)312 namematch(hp)
313 struct hostent *hp;
314 {
315 char *cp, **np;
316
317 if ((hp == NULL) || (nfshost == NULL))
318 return (1);
319
320 if (strcasecmp(nfshost, hp->h_name) == 0)
321 return (1);
322
323 if ((cp = strchr(hp->h_name, '.')) != NULL) {
324 *cp = '\0';
325 if (strcasecmp(nfshost, hp->h_name) == 0)
326 return (1);
327 }
328 for (np = hp->h_aliases; *np; np++) {
329 if (strcasecmp(nfshost, *np) == 0)
330 return (1);
331 if ((cp = strchr(*np, '.')) != NULL) {
332 *cp = '\0';
333 if (strcasecmp(nfshost, *np) == 0)
334 return (1);
335 }
336 }
337 return (0);
338 }
339
340 /*
341 * xdr routines for mount rpc's
342 */
343 int
xdr_dir(xdrsp,dirp)344 xdr_dir(xdrsp, dirp)
345 XDR *xdrsp;
346 char *dirp;
347 {
348 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
349 }
350
351 void
usage()352 usage()
353 {
354 (void)fprintf(stderr,
355 "usage: %s\n %s\n",
356 "umount [-fv] [-t fstypelist] special | node",
357 "umount -a[fv] [-h host] [-t fstypelist]");
358 exit(1);
359 }
360