Skip to content

Instantly share code, notes, and snippets.

@dvtate
Created July 14, 2023 21:02
Show Gist options
  • Save dvtate/9991b8698df872b3ff300cd763bda099 to your computer and use it in GitHub Desktop.
Save dvtate/9991b8698df872b3ff300cd763bda099 to your computer and use it in GitHub Desktop.
determine if a file/folder resides on a ssd or rotating media
#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