#ifndef lint static char *sccsid = "@(#)umount.c 1.1 85/05/30 SMI"; /* from UCB 4.8 */ #endif /* * umount */ #include <sys/param.h> #include <sys/file.h> #include <stdio.h> #include <mntent.h> #include <errno.h> #include <sys/time.h> #include <rpc/rpc.h> #include <nfs/nfs.h> #include <rpcsvc/mount.h> #include <sys/socket.h> #include <netdb.h> /* * This structure is used to build a list of mntent structures * in reverse order from /etc/mtab. */ struct mntlist { struct mntent *mntl_mnt; struct mntlist *mntl_next; }; int all = 0; int verbose = 0; char *xmalloc(); struct mntlist *mkmntlist(); struct mntent *mntdup(); int zero(); extern int errno; main(argc, argv) int argc; char **argv; { char *options; argc--, argv++; sync(); if (argc && *argv[0] == '-') { options = &argv[0][1]; while (*options) { switch (*options) { case 'a': all++; break; case 'v': verbose++; break; default: fprintf(stderr, "umount: unknown option '%c'\n", *options); usage(); } options++; } argv++; argc--; } if (all && argc) { usage(); } umountlist(argc, argv); } umountlist(argc, argv) int argc; char *argv[]; { int i, pid; int didit; struct mntent *mnt; struct mntlist *mntl, *mntcur; struct mntlist *mntrev = NULL; int tmpfd; FILE *tmpmnt; char *tmpname = "/etc/umountXXXXXX"; mktemp(tmpname); if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { perror(tmpname); exit(1); } close(tmpfd); tmpmnt = setmntent(tmpname, "w"); if (tmpmnt == NULL) { perror(tmpname); exit(1); } if (all) { pid = fork(); if (pid < 0) perror("umount: fork"); if (pid == 0) { /* child */ clnt_broadcast(MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNTALL, xdr_void, NULL, xdr_void, NULL, zero); exit(0); } } /* * get a last first list of mounted stuff, reverse list and * null out entries that get unmounted. */ for (mntl = mkmntlist(MOUNTED); mntl != NULL; mntcur = mntl, mntl = mntl->mntl_next, mntcur->mntl_next = mntrev, mntrev = mntcur) { mnt = mntl->mntl_mnt; if (strcmp(mnt->mnt_dir, "/") == 0) { continue; } if (strcmp(mnt->mnt_type, MNTTYPE_IGNORE) == 0) { continue; } if (all) { if (umountmnt(mnt)) { mntl->mntl_mnt = NULL; } continue; } for (i=0; i<argc; i++) { if ((strcmp(mnt->mnt_dir, argv[i]) == 0) || (strcmp(mnt->mnt_fsname, argv[i]) == 0) ) { if (umountmnt(mnt)) { mntl->mntl_mnt = NULL; } *argv[i] = '\0'; break; } } } for (i=0; i<argc; i++) { if (*argv[i]) { struct mntent tmpmnt; tmpmnt.mnt_fsname = NULL; tmpmnt.mnt_dir = argv[i]; tmpmnt.mnt_type = MNTTYPE_42; umountmnt(&tmpmnt); } } /* * Build new temporary mtab by walking mnt list */ for (; mntcur != NULL; mntcur = mntcur->mntl_next) { if (mntcur->mntl_mnt) { addmntent(tmpmnt, mntcur->mntl_mnt); } } endmntent(tmpmnt); /* * Move tmp mtab to real mtab */ if (rename(tmpname, MOUNTED) < 0) { perror(MOUNTED); exit(1); } } umountmnt(mnt) struct mntent *mnt; { if (unmount(mnt->mnt_dir) < 0) { if (errno != EINVAL) { perror(mnt->mnt_dir); return(0); } fprintf(stderr, "%s not mounted\n", mnt->mnt_dir); return(1); } else { if (strcmp(mnt->mnt_type, MNTTYPE_NFS) == 0) { rpctoserver(mnt); } if (verbose) { fprintf(stderr, "%s: Unmounted\n", mnt->mnt_dir); } return(1); } } usage() { fprintf(stderr, "usage: umount -a[v]\n umount [-v] <path> | <dev> ...\n"); exit(1); } rpctoserver(mnt) struct mntent *mnt; { char *p, *index(); struct sockaddr_in sin; struct hostent *hp; int s = -1; struct timeval timeout; CLIENT *client; enum clnt_stat rpc_stat; if ((p = index(mnt->mnt_fsname, ':')) == NULL) return; *p++ = 0; if ((hp = gethostbyname(mnt->mnt_fsname)) == NULL) { fprintf(stderr, "%s not in hosts database\n", mnt->mnt_fsname); return(1); } bzero(&sin, sizeof(sin)); bcopy(hp->h_addr, (char *) & sin.sin_addr, hp->h_length); sin.sin_family = AF_INET; timeout.tv_usec = 0; timeout.tv_sec = 10; if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, timeout, &s)) == NULL) { clnt_pcreateerror("Warning: umount:"); return(1); } client->cl_auth = authunix_create_default(); timeout.tv_usec = 0; timeout.tv_sec = 25; rpc_stat = clnt_call(client, MOUNTPROC_UMNT, xdr_path, &p, xdr_void, NULL, timeout); if (rpc_stat != RPC_SUCCESS) { clnt_perror(client, "Warning: umount:"); return(1); } } zero(resultsp, addrp) char *resultsp; struct sockaddr_in *addrp; { return (0); } char * xmalloc(size) int size; { char *ret; if ((ret = (char *)malloc(size)) == NULL) { fprintf(stderr, "umount: ran out of memory!\n"); exit(1); } return (ret); } struct mntent * mntdup(mnt) struct mntent *mnt; { struct mntent *new; new = (struct mntent *)xmalloc(sizeof(*new)); new->mnt_fsname = (char *)xmalloc(strlen(mnt->mnt_fsname) + 1); strcpy(new->mnt_fsname, mnt->mnt_fsname); new->mnt_dir = (char *)xmalloc(strlen(mnt->mnt_dir) + 1); strcpy(new->mnt_dir, mnt->mnt_dir); new->mnt_type = (char *)xmalloc(strlen(mnt->mnt_type) + 1); strcpy(new->mnt_type, mnt->mnt_type); new->mnt_opts = (char *)xmalloc(strlen(mnt->mnt_opts) + 1); strcpy(new->mnt_opts, mnt->mnt_opts); new->mnt_freq = mnt->mnt_freq; new->mnt_passno = mnt->mnt_passno; return (new); } struct mntlist * mkmntlist(file) char *file; { FILE *mounted; struct mntlist *mntl; struct mntlist *mntst = NULL; struct mntent *mnt; mounted = setmntent(MOUNTED, "r"); if (mounted == NULL) { perror(MOUNTED); exit(1); } while ((mnt = getmntent(mounted)) != NULL) { mntl = (struct mntlist *)xmalloc(sizeof(*mntl)); mntl->mntl_mnt = mntdup(mnt); mntl->mntl_next = mntst; mntst = mntl; } return(mntst); }