Created
July 14, 2023 21:02
-
-
Save dvtate/9991b8698df872b3ff300cd763bda099 to your computer and use it in GitHub Desktop.
determine if a file/folder resides on a ssd or rotating media
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <string> | |
#include <vector> | |
#include <algorithm> | |
#include <cstring> | |
#include <iostream> | |
#include <mntent.h> | |
#include <limits.h> | |
struct MountPointEntity { | |
struct mntent me; | |
char buff[PATH_MAX * 3]; | |
}; | |
std::vector<MountPointEntity*> getMountPoints() { | |
// /etc/mtab contains a list of all mounted devices | |
FILE* mf = setmntent("/etc/mtab", "r"); | |
if ( mf == nullptr ) | |
return {}; | |
// iterate over entries adding them to a database | |
std::vector<MountPointEntity*> ret; | |
for ( ;; ) | |
{ | |
auto* ent = new MountPointEntity; | |
if ( getmntent_r( mf, &ent->me, ent->buff, PATH_MAX * 3 ) == nullptr ) | |
{ | |
delete ent; | |
break; | |
} | |
ret.push_back(ent); | |
} | |
// Want longer dir names first since they could be subpaths | |
std::sort(ret.begin(), ret.end(), [](MountPointEntity* a, MountPointEntity* b) { | |
return strlen(a->me.mnt_dir) > strlen(b->me.mnt_dir); | |
}); | |
return ret; | |
} | |
bool isOnSSD(char* path) { | |
char p[PATH_MAX]; | |
if ( realpath(path, p) == nullptr ) | |
return false; | |
static auto mps = getMountPoints(); | |
struct mntent* me = nullptr; | |
for (auto* mp : mps) { | |
if ( strncmp( mp->me.mnt_dir, p, strlen( mp->me.mnt_dir ) ) == 0 ) { | |
me = &mp->me; | |
printf("match: %s -- %s\n", mp->me.mnt_dir, p); | |
break; | |
} | |
} | |
if ( me == nullptr ) { | |
puts("not found"); | |
return false; | |
} | |
printf("dev: %s\n", me->mnt_fsname); | |
if ( strncmp( "/dev/", me->mnt_fsname, 5 ) == 0 ) | |
me->mnt_fsname += 5; | |
std::string sysfpath = "/sys/class/block/"; | |
sysfpath += me->mnt_fsname; | |
sysfpath += "/queue/rotational"; | |
FILE* f = fopen(sysfpath.c_str(), "r"); | |
if ( f == nullptr ) { | |
puts(me->mnt_fsname); | |
puts("not in sysfs"); | |
sysfpath = "/sys/class/block/"; | |
sysfpath += me->mnt_fsname; | |
sysfpath += "/../queue/rotational"; | |
f = fopen(sysfpath.c_str(), "r"); | |
if ( f == nullptr ) { | |
puts(me->mnt_fsname); | |
puts("not in sysfs"); | |
return false; | |
} | |
} | |
const char c = fgetc(f); | |
printf("rot: %c\n", c); | |
return c == '0'; | |
// Other method that doesn't always work | |
/* | |
struct mntent minfo; | |
if ( getmntent_r(mf, &minfo) == nullptr ) { | |
endmntent(mf); | |
return false; | |
} | |
endmntent(mf); | |
std::cout <<minfo.mnt_fsname <<std::endl; | |
struct statvfs statinfo; | |
statvfs(path, &statinfo); | |
// The bitshift trick works experimentally but not documented anywhere | |
std::cout <<statinfo.f_fsid <<std::endl; | |
const int devid = (*((int*)&statinfo.f_fsid)) >> 8; | |
std::string sysfpath = "/sys/dev/block/" + std::to_string(devid) + ":0/queue/rotational"; | |
FILE* f = fopen(sysfpath.c_str(), "r"); | |
if ( f == nullptr ) | |
return false; | |
const char c = fgetc(f); | |
fclose(f); | |
return c == '0'; | |
*/ | |
} | |
int main(int argc, char** argv) { | |
if ( isOnSSD( argv[1] ) ) | |
std::cout <<"SSD\n"; | |
else | |
std::cout <<"Disk\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment