"use strict"; const Promise = require("bluebird"); const execBinary = require("../exec-binary"); const parseIECBytes = require("../parse-bytes-iec"); const parseMountOptions = require("../parse-mount-options"); const createJsonParser = require("../text-parser-json"); // TODO: Should we replace this with a read from /proc/mounts directly? // Ref. https://unix.stackexchange.com/a/18067 function mapMountList(mounts) { return mounts.map((mount) => { // Some poorly-documented pseudo-filesystems were not worth investigating mount options for, yet. For those, we silently ignore missing/unknown entries. // TODO: FUSE, UDF should eventually be removed from this list let missingOptionsAllowed = ["cgroup", "cgroup2", "bpf", "pstore", "fuse", "udf"].includes(mount.fstype); let parsedOptions = parseMountOptions(mount.fstype, mount.options); // For dealing with bind mounts, which have a path suffix, like eg.: // /dev/disk/by-uuid/692937db-d74c-4110-b55b-41a20f1b9342[/nix/store] let cleanSourceDevice = (mount.source.startsWith("/")) ? mount.source.replace(/\[.+$/, "") : null; // Pseudo-filesystems if (missingOptionsAllowed || parsedOptions.missing.length === 0) { return { id: mount.id, sourceDevice: cleanSourceDevice, isBindMount: (cleanSourceDevice != null) ? mount.source.includes("[") // FIXME: Is this actually correct? Can a square bracket ever appear in a device path legitimately? : false, // Pseudo-filesystems mountpoint: mount.target, filesystem: mount.fstype, options: parsedOptions.parsed, label: mount.label, uuid: mount.uuid, partitionLabel: mount.partlabel, partitionUUID: mount.partuuid, deviceNumber: mount["maj:min"], totalSpace: parseIECBytes(mount.size), freeSpace: parseIECBytes(mount.avail), usedSpace: parseIECBytes(mount.used), rootPath: mount.fsroot, taskID: mount.tid, optionalFields: mount["opt-fields"], propagationFlags: mount.propagation, children: (mount.children != null) ? mapMountList(mount.children) : [] }; } else { throw new Error(`Encountered unrecognized mount options for mount '${mount.target}': ${parsedOptions.missing.join(", ")}`); } }); } let columns = [ "SOURCE", "TARGET", "FSTYPE", "OPTIONS", "LABEL", "UUID", "PARTLABEL", "PARTUUID", "MAJ:MIN", "SIZE", "AVAIL", "USED", "FSROOT", "TID", "ID", "OPT-FIELDS", "PROPAGATION" ]; module.exports = function findmnt() { return Promise.try(() => { return execBinary("findmnt") .withFlags({ json: true, o: columns.join(",") }) .requireOnStdout(createJsonParser()) .execute(); }).then((output) => { return mapMountList(output.result.filesystems); }); };