From 51278b9d8fabac60c9c260e27bd5f39a9917ff3f Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Tue, 12 Dec 2023 02:12:50 -0500 Subject: [PATCH] Read from /dev instead of lsblk --- xmdev/src/main.c | 233 +++++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 128 deletions(-) diff --git a/xmdev/src/main.c b/xmdev/src/main.c index 0910625..18bbed2 100644 --- a/xmdev/src/main.c +++ b/xmdev/src/main.c @@ -12,6 +12,9 @@ #include #include +#include +#include +#include #include #include #include @@ -45,6 +48,7 @@ typedef enum { typedef struct { Widget widget; DeviceKind kind; + Bool orphaned; String name; String mountPoint; String label; @@ -52,6 +56,7 @@ typedef struct { void loadIconPixmaps (void); void refreshDevices (void); +void refreshDisks (void); Device * DeviceNew (String name, DeviceKind kind); void DeviceDelete (ConstString name); void DeviceFree (Device *this); @@ -101,145 +106,116 @@ void loadIconPixmaps (void) { dev(TTY, tty); } +Bool markDevice (XmdStringMap *map, ConstString key, void *value, void *data) { + (void)(map); + (void)(key); + (void)(data); + Device *this = value; + this->orphaned = True; + return True; +} + +Bool transferDevice (XmdStringMap *map, ConstString key, void *value, void *data) { + (void)(map); + (void)(key); + (void)(data); + Device *this = value; + if (this->orphaned) { + DeviceFree(this); + } else { + XmdStringMapSet(devices, key, value); + } + return True; +} + void refreshDevices (void) { XtUnmanageChild(container); - pid_t child = 0; - FILE *stream = XmdVaPipedExecPath ( - "lsblk", &child, "r", - "", "-P", "-o", "NAME,TYPE,MOUNTPOINTS,LABEL", NULL); - if (stream == NULL) { - /* TODO error */ - return; - } - Device *device = NULL; - while (readBlockDevice(stream, &device) != EOF) { - /* do something with device? */ - } - fclose(stream); - waitpid(child, NULL, 0); - + /* pre-mark all devices as orphaned */ + XmdStringMapIterate(devices, markDevice, NULL); + + /* refresh devices by category */ + refreshDisks(); + + /* create a new map, only moving over extant devices */ + XmdStringMap *oldMap = devices; + devices = XmdStringMapNew(); + XmdStringMapIterate(oldMap, transferDevice, NULL); + XmdStringMapFree(oldMap); + XtManageChild(container); } -int readBlockDevice (FILE *stream, Device **device) { - DeviceKind kind = DeviceKindGeneric; - String name = NULL; - String mountPoint = NULL; - String label = NULL; - - int ch = 0; - while (1) { - String key = NULL; - String value = NULL; - ch = readLsblkPair(stream, &key, &value); - - if (strcmp(key, "NAME") == 0) { - XtFree(name); - name = value; - } else if (strcmp(key, "TYPE") == 0) { - if (strcmp(value, "disk") == 0) { - kind = DeviceKindDisk; - } else if (strcmp(value, "rom") == 0) { - kind = DeviceKindRom; - } else if (strcmp(value, "part") == 0) { - kind = DeviceKindFilesystem; - } - XtFree(value); - } else if (strcmp(key, "MOUNTPOINTS") == 0) { - XtFree(mountPoint); - mountPoint = value; - } else if (strcmp(key, "LABEL") == 0) { - XtFree(label); - label = value; - } else { - XtFree(value); - } - XtFree(key); - - while ((ch = fgetc(stream)) == ' '); - if (ch == EOF || ch == '\n') break; - ungetc(ch, stream); - } - - if (name != NULL) { - *device = XmdStringMapGet(devices, name); - if (*device == NULL) { - *device = DeviceNew(name, kind); - } else { - DeviceSetKind(*device, kind); - } - DeviceSetMountPoint(*device, mountPoint); - DeviceSetLabel(*device, label); - } - - XtFree(name); - XtFree(mountPoint); - XtFree(label); - return ch; +String diskName (ConstString directory, ConstString name) { + char fullpath[PATH_MAX]; + snprintf(fullpath, XtNumber(fullpath), "%s/%s", directory, name); + char resolved[PATH_MAX]; + return XtNewString(basename(realpath(fullpath, resolved))); } -int readLsblkPair (FILE *stream, String *key, String *value) { - int ch = 0; - int escapeCh = 0; - char null = 0; +void refreshDisks (void) { + /* get disks */ + ConstString disksById = "/dev/disk/by-id"; + ConstString disksByLabel = "/dev/disk/by-label"; + ConstString disksByPartuuid = "/dev/disk/by-partuuid"; - *key = NULL; - *value = NULL; - - XmdBuffer *keyBuffer = XmdBufferNew(char); - while (isalpha(ch = fgetc(stream))) XmdBufferPush(keyBuffer, &ch); - XmdBufferPush(keyBuffer, &null); - *key = XmdBufferBreak(keyBuffer); - - fgetc(stream); /* skip = */ - - XmdBuffer *valueBuffer = XmdBufferNew(char); - enum { - stateGetString, - stateGetEscape, - - } state = stateGetString; - while (1) { - ch = fgetc(stream); - if (ch == EOF) goto end; - - switch (state) { - case stateGetString: - switch (ch) { - case '"': goto end; - case '\\': state = stateGetEscape; break; - default: XmdBufferPush(valueBuffer, &ch); break; - } - break; - - case stateGetEscape: - ch = fgetc(stream); /* skip x */ - int digit = tolower(ch); - if ( - (digit < '0' || digit > '9') && - (digit < 'a' || digit > 'f') - ) { - ungetc(ch, stream); - XmdBufferPush(valueBuffer, &escapeCh); - state = stateGetString; - break; - } - digit -= '0'; - if (digit > 9) digit -= 'a' - '9' - 1; - escapeCh *= 16; - escapeCh += digit; - break; + struct dirent **entries = NULL; + int entriesCount = scandir(disksById, &entries, NULL, alphasort); + if (entriesCount < 0) { + /* TODO error message */ + return; + } + for (int index = 0; index < entriesCount; index ++) { + struct dirent *entry = entries[index]; + if (entry->d_name[0] == '.') { + XtFree((char *)(entry)); + continue; } + String deviceName = diskName(disksById, entry->d_name); + XtFree((char *)(entry)); + + Device *device = XmdStringMapGet(devices, deviceName); + if (device == NULL) { + device = DeviceNew(deviceName, DeviceKindDisk); + } else { + device->orphaned = False; + DeviceSetKind(device, DeviceKindDisk); + } + + XtFree(deviceName); } - end: - XmdBufferPush(valueBuffer, &null); - *value = XmdBufferBreak(valueBuffer); - if (strlen(*value) == 0) { - XtFree(*value); - *value = NULL; + XtFree((char *)(entries)); + + /* determine disk types */ + DIR *dir = opendir(disksByPartuuid); + if (dir == NULL) { + /* TODO error message */ + return; } - return ch; + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') continue; + String deviceName = diskName(disksByPartuuid, entry->d_name); + Device *device = XmdStringMapGet(devices, deviceName); + if (device != NULL) DeviceSetKind(device, DeviceKindFilesystem); + XtFree(deviceName); + } + closedir(dir); + + /* determine partition labels */ + dir = opendir(disksByLabel); + if (dir == NULL) { + /* TODO error message */ + return; + } + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') continue; + String deviceName = diskName(disksByLabel, entry->d_name); + Device *device = XmdStringMapGet(devices, deviceName); + if (device != NULL) DeviceSetLabel(device, entry->d_name); + XtFree(deviceName); + } + closedir(dir); } Device *DeviceNew (String name, DeviceKind kind) { @@ -247,10 +223,11 @@ Device *DeviceNew (String name, DeviceKind kind) { this->mountPoint = NULL; this->label = NULL; this->name = XtNewString(name); + this->orphaned = False; XmString string = XmStringCreateLocalized(name); this->widget = XtVaCreateManagedWidget ( "device", xmIconGadgetClass, container, - XmNalignment, XmALIGNMENT_CENTER, + XmNalignment, XmALIGNMENT_BEGINNING, XmNlabelString, string, NULL); XmStringFree(string);