diff options
Diffstat (limited to 'src/detection/disk/disk_bsd.c')
| -rw-r--r-- | src/detection/disk/disk_bsd.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/detection/disk/disk_bsd.c b/src/detection/disk/disk_bsd.c new file mode 100644 index 0000000..9156d79 --- /dev/null +++ b/src/detection/disk/disk_bsd.c @@ -0,0 +1,214 @@ +#include "disk.h" +#include "common/mallocHelper.h" +#include "common/strutil.h" + +#include <stdalign.h> +#include <sys/mount.h> +#include <sys/stat.h> + +#ifdef __NetBSD__ + #include <sys/types.h> + #include <sys/statvfs.h> + #define statfs statvfs + #define f_flags f_flag + #define f_bsize f_frsize +#endif + +#ifdef __FreeBSD__ + #if __has_include(<libgeom.h>) + #include <libgeom.h> + +static const char* detectFsLabel(struct statfs* fs, FFDisk* disk) { + if (!ffStrStartsWith(fs->f_mntfromname, "/dev/")) { + return "Only block devices are supported"; + } + + // Detect volume label in geom tree + static struct gmesh geomTree; + static struct gclass* cLabels; + if (!cLabels) { + if (geomTree.lg_ident) { + return "Previous geom_gettree() failed"; + } + + if (geom_gettree(&geomTree) < 0) { + geomTree.lg_ident = (void*) (intptr_t) -1; + return "geom_gettree() failed"; + } + + for (cLabels = geomTree.lg_class.lh_first; cLabels && !ffStrEquals(cLabels->lg_name, "LABEL"); cLabels = cLabels->lg_class.le_next); + if (!cLabels) { + return "Class LABEL is not found"; + } + } + + for (struct ggeom* label = cLabels->lg_geom.lh_first; label; label = label->lg_geom.le_next) { + struct gprovider* provider = label->lg_provider.lh_first; + if (!provider || !ffStrEquals(label->lg_name, fs->f_mntfromname + strlen("/dev/"))) { + continue; + } + const char* str = strchr(provider->lg_name, '/'); + ffStrbufSetS(&disk->name, str ? str + 1 : provider->lg_name); + } + + return NULL; +} + #else +static const char* detectFsLabel(FF_A_UNUSED struct statfs* fs, FF_A_UNUSED FFDisk* disk) { + return "Fastfetch was compiled without libgeom support"; +} + #endif + +static void detectFsInfo(struct statfs* fs, FFDisk* disk) { + if (ffStrbufEqualS(&disk->filesystem, "zfs")) { + disk->type = !ffStrbufStartsWithS(&disk->mountFrom, "zroot/") || ffStrbufStartsWithS(&disk->mountFrom, "zroot/ROOT/") + ? FF_DISK_VOLUME_TYPE_REGULAR_BIT + : FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT; + } else if (fs->f_flags & MNT_IGNORE) { + disk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT; + } else if (!(fs->f_flags & MNT_LOCAL)) { + disk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT; + } else { + disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT; + } + + detectFsLabel(fs, disk); +} +#elif __APPLE__ + #include "common/apple/cf_helpers.h" + + #include <sys/attr.h> + #include <unistd.h> + + #ifndef MAC_OS_X_VERSION_10_15 + #define MNT_REMOVABLE 0x00000200 + #endif + +struct CmnAttrBuf { + uint32_t length; + attrreference_t nameRef; + char nameSpace[NAME_MAX * 3 + 1]; +} FF_A_PACKED; + +void detectFsInfo(struct statfs* fs, FFDisk* disk) { + if (fs->f_flags & MNT_DONTBROWSE) { + disk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT; + } else if (fs->f_flags & MNT_REMOVABLE || !(fs->f_flags & MNT_LOCAL)) { + disk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT; + } else { + disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT; + } + + alignas(4) struct CmnAttrBuf attrBuf; + if (getattrlist(disk->mountpoint.chars, &(struct attrlist) { + .bitmapcount = ATTR_BIT_MAP_COUNT, + .commonattr = ATTR_CMN_NAME, + }, + &attrBuf, + sizeof(attrBuf), + 0) == 0) { + ffStrbufInitNS(&disk->name, attrBuf.nameRef.attr_length - 1 /* excluding '\0' */, attrBuf.nameSpace); + } +} +#else +static void detectFsInfo(struct statfs* fs, FFDisk* disk) { + #ifdef MNT_IGNORE + if (fs->f_flags & MNT_IGNORE) { + disk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT; + } else + #endif + if (!(fs->f_flags & MNT_LOCAL)) { + disk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT; + } else { + disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT; + } +} +#endif + +const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) { +#ifndef __NetBSD__ + int size = getfsstat(NULL, 0, MNT_WAIT); + if (size <= 0) { + return "getfsstat(NULL, 0, MNT_WAIT) failed"; + } +#else + int size = getvfsstat(NULL, 0, ST_WAIT); + if (size <= 0) { + return "getvfsstat(NULL, 0, ST_WAIT) failed"; + } +#endif + + FF_AUTO_FREE struct statfs* buf = malloc(sizeof(*buf) * (unsigned) size); +#ifndef __NetBSD__ + if (getfsstat(buf, (int) (sizeof(*buf) * (unsigned) size), MNT_NOWAIT) <= 0) { + return "getfsstat(buf, size, MNT_NOWAIT) failed"; + } +#else + if (getvfsstat(buf, sizeof(*buf) * (unsigned) size, ST_NOWAIT) <= 0) { + return "getvfsstat(buf, size, ST_NOWAIT) failed"; + } +#endif + + for (struct statfs* fs = buf; fs < buf + size; ++fs) { + if (__builtin_expect(options->folders.length > 0, 0)) { + if (!ffStrbufSeparatedContainS(&options->folders, fs->f_mntonname, FF_DISK_FOLDER_SEPARATOR)) { + continue; + } + } else if (!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs")) { + continue; + } + + if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, fs->f_mntonname, FF_DISK_FOLDER_SEPARATOR)) { + continue; + } + + if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, fs->f_fstypename, ':')) { + continue; + } + +#ifdef __FreeBSD__ + // f_bavail and f_ffree are signed on FreeBSD... + if (fs->f_bavail < 0) { + fs->f_bavail = 0; + } + if (fs->f_ffree < 0) { + fs->f_ffree = 0; + } +#endif + + FFDisk* disk = FF_LIST_ADD(FFDisk, *disks); + + disk->bytesTotal = (uint64_t) fs->f_blocks * (uint64_t) fs->f_bsize; + disk->bytesFree = (uint64_t) fs->f_bfree * (uint64_t) fs->f_bsize; + disk->bytesAvailable = (uint64_t) fs->f_bavail * (uint64_t) fs->f_bsize; + disk->bytesUsed = 0; // To be filled in ./disk.c + + disk->filesTotal = (uint32_t) fs->f_files; + disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree; + + ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname); + ffStrbufInitS(&disk->mountpoint, fs->f_mntonname); + ffStrbufInitS(&disk->filesystem, fs->f_fstypename); + ffStrbufInit(&disk->name); + disk->type = 0; + disk->createTime = 0; + + detectFsInfo(fs, disk); + + if (fs->f_flags & MNT_RDONLY) { + disk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT; + } + +#ifdef __OpenBSD__ + #define st_birthtimespec __st_birthtim +#endif +#ifndef __DragonFly__ + struct stat st; + if (stat(fs->f_mntonname, &st) == 0 && st.st_birthtimespec.tv_sec > 0) { + disk->createTime = (uint64_t) (((uint64_t) st.st_birthtimespec.tv_sec * 1000) + ((uint64_t) st.st_birthtimespec.tv_nsec / 1000000)); + } +#endif + } + + return NULL; +} |