I am running an embedded software (written in C) on Linux kernel. I need to create an alarm on my software that checks whether an SD card is mounted on, and also find out it's capacity. I can brainstorm three ideas:
I am thinking to read and parse the file /proc/mounts
and then, use regex
and a bunch of string comparisons to check if any SD card present, or
scan and check for preferable directory name under /mnt/
using dirent
library.
Either way, I am not sure how I am going to get the memory usage on SD card, or
I could use my software to run a shell script containing df
command, outputting into a file, and then read it. It should tell me whether an SD card is present, where it is mounted on, and it's capacity.
I am sure there are plenty of easy and straightforward ways to acquire this information and feed it into my software. Perhaps a nifty library call? I did some research and saw resources on fstab
, <sys/mount.h>
, don't think these will take me any further. Does anyone have any better ideas?
I know that you didn't ask for code but here you go (I really had fun writing it).
#include <stdio.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
static int
walkdir(const char *const path, int (*visit)(const char *const, const char *const), void *data)
{
struct dirent *entry;
DIR *dir;
dir = opendir(path);
if (dir == NULL)
return -1;
while ((entry = readdir(dir)) != NULL) {
int code;
code = visit(path, entry->d_name);
if (code != 0) {
closedir(dir);
return code;
}
}
closedir(dir);
return 0;
}
static char *
file_get_content(const char *const path)
{
int file;
struct stat st;
char *text;
size_t size;
text = NULL;
file = -1;
if (stat(path, &st) == -1)
goto error;
size = st.st_size;
text = malloc(size + 1);
if (text == NULL)
goto error; // file too large, cannot read like this
file = open(path, O_RDONLY);
if (file == -1)
goto error;
if ((size = read(file, text, size)) <= 0)
goto error;
text[size] = '\0';
if (file != -1)
close(file);
return text;
error:
if (file != -1)
close(file);
free(text);
return NULL;
}
static size_t
get_size(const char *const dirpath, const char *const name)
{
char path[PATH_MAX];
char *text;
int length;
size_t size;
length = snprintf(path, sizeof(path), "%s/%s/size", dirpath, name);
if (((size_t) length) > sizeof(path))
return 0;
size = 0;
text = file_get_content(path);
if (text != NULL) {
size = strtoll(text, NULL, 10);
free(text);
}
return size;
}
static int
display_block(const char *const dirpath, const char *const name)
{
const char *block;
block = strrchr(dirpath, '/');
if (block == NULL)
return -1;
block += 1;
if (strstr(name, block) == name) {
size_t size;
// get_ the parition size
//
// Note, I had to divice the size by 2 because it didn't
// match the sizes reported by `df'.
//
// Also, it appears that it's in megabytes
// (i.e. twice the size in MB)
size = get_size(dirpath, name) / (1 << 21);
// Display the result
fprintf(stdout, "\tpartition: %s (%zu GB)\n", name, size);
}
return 0;
}
static char *
get_vendor(const char *const name)
{
char path[PATH_MAX];
int length;
char *value;
// get_ partitions
length = snprintf(path, sizeof(path), "/sys/block/%s/device/vendor", name);
if (((size_t) length) > sizeof(path))
return NULL;
value = file_get_content(path);
if (value == NULL)
return NULL;
// Make the trailing `\n' a '\0' instead
strtok(value, "\n");
return value;
}
static char *
get_model(const char *const name)
{
char path[PATH_MAX];
int length;
char *value;
// get_ partitions
length = snprintf(path, sizeof(path), "/sys/block/%s/device/model", name);
if (((size_t) length) > sizeof(path))
return NULL;
value = file_get_content(path);
if (value == NULL)
return NULL;
// Make the trailing `\n' a '\0' instead
strtok(value, "\n");
return value;
}
static int
parse_block(const char *const name)
{
char path[PATH_MAX];
int length;
char *vendor;
char *model;
// get_ partitions
length = snprintf(path, sizeof(path), "/sys/block/%s", name);
if (((size_t) length) > sizeof(path))
return -1;
vendor = get_vendor(name);
model = get_model(name);
if ((model != NULL) && (vendor != NULL)) {
fprintf(stdout, "block device: %s (%s %s)\n", name, vendor, model);
walkdir(path, display_block, NULL);
}
free(vendor);
free(model);
return 0;
}
static int
list_devices(const char *const dirpath, const char *const name)
{
if (*name == '.')
return 0;
parse_block(name);
return 0;
}
int
main(void)
{
return walkdir("/sys/block", list_devices, NULL);
}
This will show you the devices and some information about them, also the size that you are very interested in.
Note, that there is no need for them to be mounted.
You can of course, find more information in other places. Just check the appropriate directories and you will be able to get everything. For instance, there is a file removable that tells you whether the device is removable, which I think will be very useful in your case.