Read from /dev instead of lsblk
This commit is contained in:
parent
d0dd41c080
commit
51278b9d8f
233
xmdev/src/main.c
233
xmdev/src/main.c
@ -12,6 +12,9 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@ -45,6 +48,7 @@ typedef enum {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Widget widget;
|
Widget widget;
|
||||||
DeviceKind kind;
|
DeviceKind kind;
|
||||||
|
Bool orphaned;
|
||||||
String name;
|
String name;
|
||||||
String mountPoint;
|
String mountPoint;
|
||||||
String label;
|
String label;
|
||||||
@ -52,6 +56,7 @@ typedef struct {
|
|||||||
|
|
||||||
void loadIconPixmaps (void);
|
void loadIconPixmaps (void);
|
||||||
void refreshDevices (void);
|
void refreshDevices (void);
|
||||||
|
void refreshDisks (void);
|
||||||
Device * DeviceNew (String name, DeviceKind kind);
|
Device * DeviceNew (String name, DeviceKind kind);
|
||||||
void DeviceDelete (ConstString name);
|
void DeviceDelete (ConstString name);
|
||||||
void DeviceFree (Device *this);
|
void DeviceFree (Device *this);
|
||||||
@ -101,145 +106,116 @@ void loadIconPixmaps (void) {
|
|||||||
dev(TTY, tty);
|
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) {
|
void refreshDevices (void) {
|
||||||
XtUnmanageChild(container);
|
XtUnmanageChild(container);
|
||||||
|
|
||||||
pid_t child = 0;
|
/* pre-mark all devices as orphaned */
|
||||||
FILE *stream = XmdVaPipedExecPath (
|
XmdStringMapIterate(devices, markDevice, NULL);
|
||||||
"lsblk", &child, "r",
|
|
||||||
"", "-P", "-o", "NAME,TYPE,MOUNTPOINTS,LABEL", NULL);
|
/* refresh devices by category */
|
||||||
if (stream == NULL) {
|
refreshDisks();
|
||||||
/* TODO error */
|
|
||||||
return;
|
/* create a new map, only moving over extant devices */
|
||||||
}
|
XmdStringMap *oldMap = devices;
|
||||||
Device *device = NULL;
|
devices = XmdStringMapNew();
|
||||||
while (readBlockDevice(stream, &device) != EOF) {
|
XmdStringMapIterate(oldMap, transferDevice, NULL);
|
||||||
/* do something with device? */
|
XmdStringMapFree(oldMap);
|
||||||
}
|
|
||||||
fclose(stream);
|
|
||||||
waitpid(child, NULL, 0);
|
|
||||||
|
|
||||||
XtManageChild(container);
|
XtManageChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
int readBlockDevice (FILE *stream, Device **device) {
|
String diskName (ConstString directory, ConstString name) {
|
||||||
DeviceKind kind = DeviceKindGeneric;
|
char fullpath[PATH_MAX];
|
||||||
String name = NULL;
|
snprintf(fullpath, XtNumber(fullpath), "%s/%s", directory, name);
|
||||||
String mountPoint = NULL;
|
char resolved[PATH_MAX];
|
||||||
String label = NULL;
|
return XtNewString(basename(realpath(fullpath, resolved)));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int readLsblkPair (FILE *stream, String *key, String *value) {
|
void refreshDisks (void) {
|
||||||
int ch = 0;
|
/* get disks */
|
||||||
int escapeCh = 0;
|
ConstString disksById = "/dev/disk/by-id";
|
||||||
char null = 0;
|
ConstString disksByLabel = "/dev/disk/by-label";
|
||||||
|
ConstString disksByPartuuid = "/dev/disk/by-partuuid";
|
||||||
|
|
||||||
*key = NULL;
|
struct dirent **entries = NULL;
|
||||||
*value = NULL;
|
int entriesCount = scandir(disksById, &entries, NULL, alphasort);
|
||||||
|
if (entriesCount < 0) {
|
||||||
XmdBuffer *keyBuffer = XmdBufferNew(char);
|
/* TODO error message */
|
||||||
while (isalpha(ch = fgetc(stream))) XmdBufferPush(keyBuffer, &ch);
|
return;
|
||||||
XmdBufferPush(keyBuffer, &null);
|
}
|
||||||
*key = XmdBufferBreak(keyBuffer);
|
for (int index = 0; index < entriesCount; index ++) {
|
||||||
|
struct dirent *entry = entries[index];
|
||||||
fgetc(stream); /* skip = */
|
if (entry->d_name[0] == '.') {
|
||||||
|
XtFree((char *)(entry));
|
||||||
XmdBuffer *valueBuffer = XmdBufferNew(char);
|
continue;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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:
|
XtFree((char *)(entries));
|
||||||
XmdBufferPush(valueBuffer, &null);
|
|
||||||
*value = XmdBufferBreak(valueBuffer);
|
/* determine disk types */
|
||||||
if (strlen(*value) == 0) {
|
DIR *dir = opendir(disksByPartuuid);
|
||||||
XtFree(*value);
|
if (dir == NULL) {
|
||||||
*value = 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) {
|
Device *DeviceNew (String name, DeviceKind kind) {
|
||||||
@ -247,10 +223,11 @@ Device *DeviceNew (String name, DeviceKind kind) {
|
|||||||
this->mountPoint = NULL;
|
this->mountPoint = NULL;
|
||||||
this->label = NULL;
|
this->label = NULL;
|
||||||
this->name = XtNewString(name);
|
this->name = XtNewString(name);
|
||||||
|
this->orphaned = False;
|
||||||
XmString string = XmStringCreateLocalized(name);
|
XmString string = XmStringCreateLocalized(name);
|
||||||
this->widget = XtVaCreateManagedWidget (
|
this->widget = XtVaCreateManagedWidget (
|
||||||
"device", xmIconGadgetClass, container,
|
"device", xmIconGadgetClass, container,
|
||||||
XmNalignment, XmALIGNMENT_CENTER,
|
XmNalignment, XmALIGNMENT_BEGINNING,
|
||||||
XmNlabelString, string,
|
XmNlabelString, string,
|
||||||
NULL);
|
NULL);
|
||||||
XmStringFree(string);
|
XmStringFree(string);
|
||||||
|
Loading…
Reference in New Issue
Block a user