The following logic provides iteration over /proc/<PID>/maps
for a Linux process. What I'm primarily (though not solely) interested in for this review is whether or not I've made any invalid assumptions about the layout of the maps
file.
iterate_map.h
#ifndef REAP_ITERATE_MAP_H
#define REAP_ITERATE_MAP_H
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#define REAP_PATH_SIZE 256
enum reapRetValue {
REAP_RET_OK, /**< The function was successful.*/
REAP_RET_DONE, /**< The iteration is finished.*/
REAP_RET_BAD_USAGE, /**< A funciton was called with invalid arguments.*/
REAP_RET_OUT_OF_MEMORY, /**< A memory allocation failed.*/
REAP_RET_NO_PERMISSION, /**< No permission to access a requested resource.*/
REAP_RET_NOT_FOUND, /**< A requested resource was not found.*/
REAP_RET_TOO_MANY_LINKS, /**< Too many symbolic links encountered.*/
REAP_RET_FILE_READ, /**< Failed to read from a file.*/
REAP_RET_OTHER, /**< Catch-all error.*/
};
/**
* @brief Iterates over all line in a /proc/<PID>/maps file.
*
* @note User code should not access the iterator's fields.
*/
typedef struct reapMapIterator {
FILE *file;
} reapMapIterator;
/**
* @brief Result generated by a reapMapIterator.
*/
typedef struct reapMapResult {
unsigned long start; /**< The start of the memory section.*/
unsigned long end; /**< The end of the memory section.*/
unsigned int offset; /**< The offset of the memory section in the referent file.*/
int permissions; /**< The permissions of the memory section.*/
dev_t device; /**< The device number of the referent file.*/
ino_t inode; /**< The inode of the referent file.*/
char name[REAP_PATH_SIZE]; /**< The name of the referent file.*/
} reapMapResult;
/**
* @brief Initializes an iterator.
*
* @param pid The PID.
* @param iterator A pointer to the iterator.
*
* @return REAP_RET_OK if successful and an error code otherwise.
*/
int
reapMapIteratorInit(pid_t pid, reapMapIterator *iterator);
/**
* @brief Closes an iterator.
*
* @param iterator A pointer to the iterator.
*/
void
reapMapIteratorClose(reapMapIterator *iterator);
/**
* @brief Gets the next result.
*
* @param iterator A pointer to the iterator.
* @param[out] result A pointer to the result to be populated.
*
* @return REAP_RET_OK if a result was found, REAP_RET_DONE if the iteration is finished, and an
* error code otherwise.
*/
int
reapMapIteratorNext(const reapMapIterator *iterator, reapMapResult *result);
#endif // REAP_ITERATE_MAP_H
iterate_map.c
#include <errno.h>
#include <string.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <reap/iterate_map.h>
static int
translateErrno(void)
{
switch (errno) {
case EINVAL: return REAP_RET_BAD_USAGE;
case EACCES: return REAP_RET_NO_PERMISSION;
case ELOOP: return REAP_RET_TOO_MANY_LINKS;
case ENOENT:
case ENOTDIR:
case EIO: return REAP_RET_FILE_READ;
case ENOMEM: return REAP_RET_OUT_OF_MEMORY;
default: return REAP_RET_OTHER;
}
}
int
reapMapIteratorInit(pid_t pid, reapMapIterator *iterator)
{
char buffer[100];
if (pid <= 0 || !iterator) {
return REAP_RET_BAD_USAGE;
}
snprintf(buffer, sizeof(buffer), "/proc/%li/maps", (long)pid);
iterator->file = fopen(buffer, "r");
if (!iterator->file) {
return translateErrno();
}
return REAP_RET_OK;
}
void
reapMapIteratorClose(reapMapIterator *iterator)
{
if (iterator && iterator->file) {
fclose(iterator->file);
iterator->file = NULL;
}
}
int
reapMapIteratorNext(const reapMapIterator *iterator, reapMapResult *result)
{
int num_matches;
unsigned int major, minor;
unsigned long inode;
char r, w, x;
char line[256];
if (!iterator || !iterator->file || !result) {
return REAP_RET_BAD_USAGE;
}
if (!fgets(line, sizeof(line), iterator->file)) {
if (ferror(iterator->file)) {
return REAP_RET_FILE_READ;
}
else {
return REAP_RET_DONE;
}
}
num_matches = sscanf(line, "%lx-%lx %c%c%c%*c %x %x:%x %lu %s", &result->start, &result->end, &r, &w, &x,
&result->offset, &major, &minor, &inode, result->name);
if (num_matches < 9) {
return REAP_RET_OTHER;
}
if (num_matches == 9) {
result->name[0] = '\0';
}
result->permissions = 0;
if (r == 'r') {
result->permissions |= PROT_READ;
}
if (w == 'w') {
result->permissions |= PROT_WRITE;
}
if (x == 'x') {
result->permissions |= PROT_EXEC;
}
result->device = makedev(major, minor);
result->inode = inode;
return REAP_RET_OK;
}
#define REAP_PATH_SIZE 256
? 256 deserves some explanation. \$\endgroup\$PATH_SIZE
? \$\endgroup\$PATH_SIZE
, why undocumented? \$\endgroup\$PATH_SIZE
in length. \$\endgroup\$