shperm/shperm.c

162 lines
4.6 KiB
C

#include <stdio.h>
#include <linux/limits.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#define PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING 1
#define PERMISSION_USER 2
#define PERMISSION_GROUP 1
#define PERMISSION_OTHERS 0
#define PERMISSION_BYTES 3 // rwx
#define PERMISSION_ENTITIES 3 // user group others
const int MAX_PERMISSIONS = PERMISSION_ENTITIES * PERMISSION_BYTES;
typedef struct {
char* username;
char* groupname;
char permissionStr[3][4];
char* path;
} line;
line* lines;
int linesNo = 0;
int maxUsername = 0;
int maxGroupname = 0;
void mallocLines() {
// add one line to the lines array
if (linesNo == 1) {
lines = malloc(sizeof(*lines));
} else {
if ((lines = realloc(lines, linesNo * sizeof(*lines))) == NULL) {
fprintf(stderr, "Error allocating memory\n");
exit(4);
}
}
}
void addPermission2Line(int idx, int permissions) {
strcpy(lines[idx].permissionStr[PERMISSION_USER], "---");
strcpy(lines[idx].permissionStr[PERMISSION_GROUP], "---");
strcpy(lines[idx].permissionStr[PERMISSION_OTHERS], "---");
for (int i = 0; i < MAX_PERMISSIONS; i++) {
// clear out all permissions except the i'th bit
int tmpPermission = permissions & (1 << i);
int permissionUGO = i / PERMISSION_ENTITIES;
// -1 because of 0-based index
int permissionRWX = (MAX_PERMISSIONS - i - 1) % PERMISSION_BYTES;
// read
if (tmpPermission & S_IRUSR
|| tmpPermission & S_IRGRP
|| tmpPermission & S_IROTH) {
lines[idx].permissionStr[permissionUGO][permissionRWX] = 'r';
}
// write
if (tmpPermission & S_IWUSR
|| tmpPermission & S_IWGRP
|| tmpPermission & S_IWOTH) {
lines[idx].permissionStr[permissionUGO][permissionRWX] = 'w';
}
// execute
if (tmpPermission & S_IXUSR
|| tmpPermission & S_IXGRP
|| tmpPermission & S_IXOTH) {
lines[idx].permissionStr[permissionUGO][permissionRWX] = 'x';
}
}
}
void addLine(char* path, int permissions, int uid, int gid) {
linesNo++;
// allocate memory for another line
mallocLines();
// calculate line (index) we are at, which is 0-based (thus -1)
int idx = linesNo - 1;
// add user
struct passwd* user = getpwuid(uid);
lines[idx].username = malloc(strlen(user->pw_name) + PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING);
strcpy(lines[idx].username, user->pw_name);
if (maxUsername < strlen(lines[idx].username)) {
maxUsername = strlen(lines[idx].username);
}
// add group
struct group* group = getgrgid(gid);
lines[idx].groupname = malloc(strlen(group->gr_name) + PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING);
strcpy(lines[idx].groupname, group->gr_name);
if (maxGroupname < strlen(lines[idx].groupname)) {
maxGroupname = strlen(lines[idx].groupname);
}
// calculate and add permission
addPermission2Line(idx, permissions);
// add current path
lines[idx].path = malloc(strlen(path) + PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING);
strcpy(lines[idx].path, path);
}
void dumpLines() {
for (int i = 0; i < linesNo; i++) {
printf("%s ", lines[i].permissionStr[PERMISSION_USER]);
printf("%s ", lines[i].permissionStr[PERMISSION_GROUP]);
printf("%s ", lines[i].permissionStr[PERMISSION_OTHERS]);
printf("%-*s ", maxUsername, lines[i].username);
printf("%-*s ", maxGroupname, lines[i].groupname);
printf("%s\n", lines[i].path);
}
}
int main(int argc, char* argv[]) {
if (argc > 2) {
fprintf(stderr, "Usage: %s [file or directory]\n", argv[0]);
exit(1);
}
char* path;
char* startpath;
path = malloc(PATH_MAX);
if (argc == 1) {
startpath = ".";
} else {
startpath = argv[1];
}
if (realpath(startpath, path)) {
char* base;
do {
struct stat sb;
base = basename(path);
if (stat(path, &sb) == 0) {
addLine(path, sb.st_mode, sb.st_uid, sb.st_gid);
} else {
fprintf(stderr, "Error (%d): %s: %s\n", errno, strerror(errno), path);
exit(3);
}
path = dirname(path);
} while (strcmp(base, "/"));
dumpLines();
} else {
fprintf(stderr, "Error (%d): %s: %s\n", errno, strerror(errno), path);
exit(2);
}
free(path);
}