
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/loop.h>
#include <errno.h>

#define LOOPDEV_MAXLEN 64
#define LOOP_MAJOR 7

static int is_loop(char *dev)
{
    struct stat st;
    int ret = 0;

    if (stat(dev, &st) == 0) {
        if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
            ret = 1;
        }
    }

    return ret;
}

static int is_loop_mount(const char* path, char *loopdev)
{
    FILE* f;
    int count;
    char device[256];
    char mount_path[256];
    char rest[256];
    int result = 0;
    
    f = fopen("/proc/mounts", "r");
    if (!f) {
        fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno));
        return -1;
    }

    do {
        count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
        if (count == 3) {
            if (is_loop(device) && strcmp(path, mount_path) == 0) {
                strlcpy(loopdev, device, LOOPDEV_MAXLEN);
                result = 1;
                break;
            }
        }
    } while (count == 3);

    fclose(f);
    return result;
}

int main(int argc, char *argv[])
{
    int loop, loop_fd;
    char loopdev[LOOPDEV_MAXLEN];

    if(argc != 2) {
        fprintf(stderr,"umount <path>\n");
        return 1;
    }

    loop = is_loop_mount(argv[1], loopdev);
    if (umount(argv[1])) {
        fprintf(stderr, "failed: %s\n", strerror(errno));
        return 1;
    }

    if (loop) {
        // free the loop device
        loop_fd = open(loopdev, O_RDONLY);
        if (loop_fd < 0) {
            fprintf(stderr, "open loop device failed: %s\n", strerror(errno));
            return 1;
        }
        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
            fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno));
            return 1;
        }

        close(loop_fd);
    }

    return 0;
}
