/*
 * $Id: unmount.c,v 1.15 1996/03/09 06:09:18 ghudson Exp $
 *
 * Copyright (c) 1988,1991 by the Massachusetts Institute of Technology.
 *
 * For redistribution rights, see "mit-copyright.h"
 */

static char *rcsid_mount_c = "$Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/attach/unmount.c,v 1.15 1996/03/09 06:09:18 ghudson Exp $";

#include "attach.h"
#include <sys/stat.h>

#if !defined(ultrix) && !defined(_IBMR2) && !defined(__NetBSD__)
#include <mntent.h>
#endif

#if defined(_AIX) && (AIXV < 30)
#include <rpc/nfsmount.h>
#include <rpc/rpcmount.h>
#endif

#ifdef _AIX
#define unmount(x) umount(x)
#endif

#ifdef _IBMR2
#include <sys/id.h>
#endif

#ifdef linux
#include <rpcsvc/mount.h>
#endif

/*
 * Unmount a filesystem.
 */
unmount_42(errname, mntpt, dev)
	char *errname;
	char *mntpt;
	char *dev;
{
	int status;

#ifdef _IBMR2
	if (setuidx(ID_REAL|ID_EFFECTIVE, 0))
#else
	if (setreuid(0,0))
#endif
	{
		fprintf(stderr,"%s: unable to change the uid to 0\n", errname);
		return(FAILURE);
	}

	switch (fork()) {
	case -1:
		fprintf(stderr, "%s: unable to fork\n", errname);
		return(FAILURE);
		/* NOTREACHED */
	case 0:
		execl(UMOUNT_CMD, UMOUNT_CMD, mntpt, (char *)0);
		exit(1);
		/* NOTREACHED */
	default:
		wait(&status);
		break;
	}
	return((status == 0 || !is_mountpoint(mntpt)) ? SUCCESS : FAILURE);
}

#if defined(SOLARIS) || defined(__NetBSD__) || defined(linux)
bool_t
xdr_path(xdrs, pathp)
        XDR *xdrs;
        char **pathp;
{
        if (xdr_string(xdrs, pathp, 1024)) {
                return(TRUE);
        }
        return(FALSE);
}
#endif

#if defined NFS
/*
 * Unmount an NFS filesystem
 */
nfs_unmount(errname, host, hostaddr, mntpt, rmntpt)
    char *errname;
    char *host;
    struct in_addr hostaddr;
    char *mntpt;
    char *rmntpt;
{
    static struct sockaddr_in sin;
    struct timeval timeout;
    CLIENT *client;
    enum clnt_stat rpc_stat;
    struct stat statbuf_mntpt, statbuf_parent;
    char parent_name[MAXPATHLEN];

    if (unmount_42(errname, mntpt, NULL) == FAILURE)
	return (FAILURE);

    /*
     * If we can't contact the host, don't bother complaining;
     * it won't actually hurt anything except that hosts rmtab.
     */
    if (errored_out(hostaddr))
	return (SUCCESS);

    if ((client = (CLIENT *)rpc_create(hostaddr, &sin)) == NULL) {
	fprintf(stderr,
		"%s: Server %s not responding\n",
		errname, host);
	return (SUCCESS);
    }

    client->cl_auth = spoofunix_create_default(spoofhost, real_uid);

    timeout.tv_usec = 0;
    timeout.tv_sec = 20;
    rpc_stat = clnt_call(client, MOUNTPROC_UMNT, xdr_path, &rmntpt,
			 xdr_void, NULL, timeout);
    if (rpc_stat != RPC_SUCCESS) {
	mark_errored(hostaddr);
	switch (rpc_stat) {
	case RPC_TIMEDOUT:
	    fprintf(stderr, "%s: Timeout while contacting mount daemon on %s\n",
		    errname, host);
	    break;
	case RPC_AUTHERROR:
	    fprintf(stderr, "%s: Authentication failed\n",
		    errname, host);
	    break;
	case RPC_PMAPFAILURE:
	    fprintf(stderr, "%s: Can't find mount daemon on %s\n",
		    errname, host);
	    break;
	case RPC_PROGUNAVAIL:
	case RPC_PROGNOTREGISTERED:
	    fprintf(stderr, "%s: Mount daemon not available on %s\n",
		    errname, host);
	    break;
	default:
	    fprintf(stderr, "%s: System error contacting server %s\n",
		    errname, host);
	    break;
	}
	if (debug_flag)
	    clnt_perror(client, "RPC return status");
	return (SUCCESS);
    } 
    return (SUCCESS);
}
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

int is_mountpoint (dirname)
    char *dirname;
{
    struct stat rootstat, pointstat;
    char *parent;
    int len;

    parent = strdup(dirname);
    len = strlen(parent) - 1;
    while (dirname[len] == '/')
	len--;
    while (len > 0 && dirname[len] != '/')
	len--;
    parent[len + 1] = 0;

    if (stat(parent, &rootstat) < 0) {
	free(parent);
	return (FALSE);
    }
    free(parent);
    if (stat(dirname, &pointstat) < 0)
	return (FALSE);
    return (rootstat.st_dev != pointstat.st_dev);
}

