Due to OpenWrt issue 13873 the author needed a version of the mountpoint command for OpenWrt. Since they wanted to learn ucode, they coded the command in this interesting ECMAscript-like language1. This may be moot as enabling the busybox mountpoint applet could be more space-efficient, but the author enjoyed the exercise.

The following code is a fairly quick and dirty tranlsation of mountpoint from util-linux, written in ‘C’, to this code written in ucode.

Comments, suggestions and discussion of the following code should be done on the mountpoint-ucode Gist.

With the code in place, you can issue mountpoint /path/to/check which returns 0 (POSIX shell true) if /path/to/check is a mounted mountpoint, 1 if is not a mounted mountpoint, unless an error occurs, in which case the script returns -1 (255).

mountpoint -v /path/to/check will show a written message such as:
/path/to/check is a mountpoint.

mountpoint -vv /path/to/check will additionally output a message like Could not stat '/path/to/check' if there is no file or directory at path/to/check.


Place the following script as /usr/bin/mountpoint on a device with ucode installed, and make it executable (chmod 0755 /usr/bin/mountpoint).

#!/usr/bin/env ucode

import { print_is_mountpoint } from "mountpoint";

let args = ARGV;

const arg1 = shift(args);

let do_message = false;
let show_errors = false;

if (arg1 == "-v") {
    do_message = true;
} else if (arg1 == "-vv") {
    do_message = true;
    show_errors = true;
} else {
    unshift(args, arg1);
}

exit(print_is_mountpoint(join(" ", args), do_message, show_errors));

And place the following module as /usr/share/ucode/mountpoint.uc.

// based on https://github.com/util-linux/util-linux/blob/master/sys-utils/mountpoint.c

import { access, dirname, open, realpath, stat } from 'fs';

function _is_dm_devname(canonical) {

    let dmpath = null;

    const spos = rindex(canonical, "/");
    if (spos != null) {
        dmpath = substr(canonical, spos + 1);
    } else {
        return {
            error: true,
            dmpath: null,
            error_message: "Not a device path"
        };
    }

    const can_stat = stat(canonical);

    if (can_stat == null) {
        return {
            error: true,
            dmpath: null,
            error_message: sprintf("Unable to access path %s", canonical)
        };
    }

    if (
        (length(dmpath) < 5) ||
        (substr(dmpath, 0, 4) != "/dm-") ||
        (int(substr(dmpath, 4)) == NaN) ||
        (can_stat.type != "block")
    ) {
        return {
            error: false,
            dmpath: null,
            error_message: null
        };
    }

    return {
        error: false,
        dmpath: dmpath,
        error_message: null
    };
}

function _canonicalize_dm_name(path) {

    if (path == null) {
        return {
            error: true,
            dmpath: null,
            error_message: "No input path"
        };
    }

    const fpath = sprintf("/sys/block/%s/dm/name", path);
    const f = open(fpath, "r");
    if (f == null) {
        return {
            error: true,
            dmpath: null,
            error_message: sprintf("Unable to open '%s'", fpath)
        };
    }

    const dmname = f.read("\n");
    f.close();

    if (dmname == null) {
        return {
            error: true,
            dmpath: null,
            error_message: sprintf("Failed to read '%s'", fpath)
        };
    }

    const dmpath = sprintf("/dev/mapper/%s", dmname);
    if (!access(dmpath)) {
        return {
            error: true,
            dmpath: null,
            error_message: sprintf("Unable to access '%s'", dmpath)
        };
    }

    return {
        error: false,
        dmpath: dmpath,
        error_message: null
    };
}

function _canonicalize_device_path(path) {

    if (!path) {
        return {
            error: true,
            canonical: null,
            error_message: "No input path"
        };
    }

    let canonical = realpath(path);
    if (!canonical) {
        return {
            error: true,
            canonical: null,
            error_message: sprintf("'%s' has no canonical path", path)
        };
    }

    const dmname_result = _is_dm_devname(canonical);
    if (!dmname_result.error) {
        if (dmname_result.dmname != null) {
            const dmcanonical_result = _canonicalize_dm_name(dmname_result.dmname);
            if (dmcanonical_result.dmname != null) {
                canonical = dmcanonical_result.dmname;
            } else if (dmcanonical_result.error) {
                return {
                    error: true,
                    canonical: null,
                    error_message: sprintf("'%s' could not be canonicalized: %s", path, dmcanonical_result.error_message)
                };
            }
        }
    } else if (dmname_result.error_message != "Not a device path") {
        return {
            error: true,
            canonical: null,
            error_message: sprintf("'%s' could not be read: %s", canonical, dmname_result.error_message)
        };
    }
    return {
        error: false,
        canonical: canonical,
        error_message: null
    };
}

function _dir_to_device(in_stat, in_path) {

    if (in_path == null) {
        return {
            error: true,
            device: null,
            error_message: "No input path"
        };
    }

    const canonical_result = _canonicalize_device_path(in_path);

    if (canonical_result.error) {
        return {
            error: true,
            device: null,
            error_message: canonical_result.error_message
        };
    }

    const canstat_result = stat(canonical_result.canonical);

    if (canstat_result == null) {
        return {
            error: true,
            device: null,
            error_message: sprintf("Could not stat '%s' (canonical path for '%s')", canonical_result.canonical, in_path)
        };
    }

    let parent_path = sprintf("%s/..", canonical_result.canonical);

    if (canstat_result.type != "directory") {
        parent_path = dirname(canonical_result.canonical);
    }

    const parent_stat = stat(parent_path);

    if (parent_stat == null) {
        return {
            error: true,
            device: null,
            error_message: sprintf("Could not stat parent directory of '%s' (canonical path for '%s')", canonical_result.canonical, in_path)
        };
    }

    if ((in_stat.dev.major != parent_stat.dev.major) || (in_stat.dev.minor != parent_stat.dev.minor) || (in_stat.inode == parent_stat.inode)) {
        return {
            error: false,
            device: in_stat.dev,
            error_message: null
        };
    }

    return {
        error: false,
        device: null,
        error_message: null
    };
}

function _is_mountpoint(path) {

    const path_stat = stat(path);
    if (path_stat == null) {
        return {
            error: true,
            is_mountpoint: null,
            device: null,
            error_message: sprintf("Could not stat '%s'", path)
        };
    }

    const path_device_result = _dir_to_device(path_stat, path);

    if (path_device_result.error) {
        return {
            error: true,
            is_mountpoint: null,
            device: null,
            error_message: sprintf("Could not get device for '%s': %s", path, path_device_result.error_message)
        };
    } else {
        return {
            error: false,
            is_mountpoint: (path_device_result.device != null),
            device: path_device_result.device,
            error_message: null
        }
    }
}

function is_mountpoint(path, show_error) {
    const is_mp_result = _is_mountpoint(path);
    if (is_mp_result.error) {
        if (show_error) {
            printf("%s\n", is_mp_result.error_message);
        }
        return -1;

    } else {
        return (is_mp_result.is_mountpoint ? 0 : 1);
    }
}

function print_is_mountpoint(path, show_message, show_error) {
    const is_mp = is_mountpoint(path, show_error);

    if (is_mp == -1) {
        exit(-1);
    }

    if (is_mp == 0) {
        if (show_message) {
            printf("%s is a mountpoint\n", path);
        }
        exit(0);
    } else {
        if (show_message) {
            printf("%s is not a mountpoint\n", path);
        }
        exit(1);
    }
}

export { is_mountpoint, print_is_mountpoint };

  1. Javascript is an ECMAscript language ↩︎