You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
6.0 KiB
C

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
/*
* Originally written by Alexander Vdolainen <avdolainen@gmail.com>
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <getopt.h>
#include <mntent.h>
#include <blkid/blkid.h>
#define TOOLMODE_CMD 1
#define TOOLMODE_INFO 2
static void __print_version(void)
{
fprintf(stdout, "DSB user space daemon control tool version: 0.1\n\n");
fprintf(stdout, "Copyright (c) 2015-2016 Alexander Vdolainen.\nEmail: avdolainen@gmail.com\n\n");
return;
}
static void __print_help(void)
{
fprintf(stdout, "Usage: dsbfcntl [options]\nOptions:\n");
fprintf(stdout, " --file-info(-i)\t Get file information required to set rules.\n");
fprintf(stdout, " --control-command(-c) \"<command>\"\t Command to send to the DSB userspace daemon.\n");
fprintf(stdout, " --unix-socket-path(-u) <file>\t Use <file> as the unix socket name.\n");
fprintf(stdout, " --help(-h)\t Print there help message\n");
fprintf(stdout, " --version(-v)\t Print version information\n");
fprintf(stdout, "\nFor further information check out provided documentation.\n");
return;
}
static int __print_fileinfo(const char *fpath)
{
int r = 0;
struct stat buf;
FILE* fstab = NULL;
struct mntent *e;
char *devname = NULL;
char _fpath[4096];
uint64_t inode_num = 0;
blkid_probe pr;
const char *uuid;
r = stat(fpath, &buf);
if(r) {
fprintf(stderr, "FAILED: %s\n", strerror(r));
return r;
} else inode_num = buf.st_ino; /* get inode number */
/* ok now we need to get full path if required */
if(*fpath != '/') {
snprintf(_fpath, 4096, "%s/%s", get_current_dir_name(), fpath);
} else strcpy(_fpath, fpath);
fprintf(stdout, "Full pathname: %s\n", _fpath);
fstab = setmntent("/etc/mtab", "r");
/* e->mnt_dir is our hitler, mnt_fsname is a device */
while ((e = getmntent(fstab))) {
if(strlen(_fpath) < strlen(e->mnt_dir)) {
continue; /* not so interesting */
} else if(!strncmp(_fpath, e->mnt_dir, strlen(e->mnt_dir))) {
devname = strdup(e->mnt_fsname);
if(!devname) { r = ENOMEM; goto __fini; }
}
}
fprintf(stdout, "Root device of the file is: %s\n", devname);
fprintf(stdout, "File object inode number is: %lu\n", inode_num);
pr = blkid_new_probe_from_filename(devname);
if(!pr) {
r = EINVAL;
fprintf(stderr, "FAILED: %s\n", strerror(r)); goto __fini;
}
blkid_do_probe(pr);
blkid_probe_lookup_value(pr, "UUID", &uuid, NULL);
fprintf(stdout, "Root device UUID=%s\n", uuid);
blkid_free_probe(pr);
__fini:
endmntent(fstab);
if(devname) free(devname);
return r;
}
static int __execute_cmd(const char *unxsckpath, const char *ctrlcmd)
{
int r = 0, c, s, len;
char *buf = malloc(4096);
struct sockaddr_un remote;
if(!buf) return ENOMEM;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
r = errno;
goto __fini0;
}
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, unxsckpath);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
r = errno;
goto __fini;
}
if(send(s, ctrlcmd, strlen(ctrlcmd), 0) == -1) {
r = errno;
goto __fini;
}
while((c = recv(s, buf, 4096, 0)) != 0) {
if(c < 0) {
r = errno;
goto __fini;
}
fprintf(stdout, "%s", buf);
}
__fini:
close(s);
__fini0:
free(buf);
return r;
}
int main(int argc, char **argv)
{
int toolmode = 0, c, r = 0;
char *unxsckpath = NULL;
char *ctrlcmd = NULL;
char *fpath = NULL;
while(1) {
static struct option long_options[] = {
/* These options a generic ones. */
{"help", no_argument, NULL, 'h'}, /* print out help and version info */
{"version", no_argument, NULL, 'v'}, /* just out a version info */
/* The following options about system. */
{"control-command", required_argument, NULL, 'c'},
{"unix-socket-path", required_argument, NULL, 'u'},
{"file-info", required_argument, NULL, 'i'},
{NULL, 0, NULL, 0},
};
/* getopt_long stores the option index here. */
int option_index = 0;
if((c = getopt_long(argc, argv, "hvc:u:i:", long_options,
&option_index)) == -1) break;
switch (c) {
case 'h':
__print_help();
return 0;
break;
case 'v':
__print_version();
return 0;
break;
case 'c':
if(!toolmode || toolmode == TOOLMODE_CMD) toolmode = TOOLMODE_CMD;
else {
fprintf(stderr, "Illegal mode given.\n");
r = -EINVAL;
goto __fails;
}
if(!(ctrlcmd = strdup(optarg))) { r = -ENOMEM; goto __fails; }
break;
case 'u':
if(!toolmode || toolmode == TOOLMODE_CMD) toolmode = TOOLMODE_CMD;
else {
fprintf(stderr, "Illegal mode given.\n");
r = -EINVAL;
goto __fails;
}
if(!(unxsckpath = strdup(optarg))) { r = -ENOMEM; goto __fails; }
break;
case 'i':
if(!toolmode || toolmode == TOOLMODE_INFO) toolmode = TOOLMODE_INFO;
else {
fprintf(stderr, "Illegal mode given.\n");
r = -EINVAL;
goto __fails;
}
if(!(fpath = strdup(optarg))) { r = -ENOMEM; goto __fails; }
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* run it */
switch(toolmode) {
case TOOLMODE_CMD:
if(!unxsckpath) {
fprintf(stderr, "FAILED: Unix socket path doesn't pointed.\n");
goto __einval;
}
if(!ctrlcmd) {
fprintf(stderr, "FAILED: Command is absent.\n");
goto __einval;
}
r = __execute_cmd(unxsckpath, ctrlcmd);
break;
case TOOLMODE_INFO:
if(!fpath) {
fprintf(stderr, "FAILED: No input filename(s).\n");
goto __einval;
}
r = __print_fileinfo(fpath);
break;
default:
fprintf(stderr, "FAILED: Incorrect options given.\n");
__einval:
__print_version();
__print_help();
return -EINVAL;
break;
}
__fails:
if(unxsckpath) free(unxsckpath);
if(ctrlcmd) free(ctrlcmd);
if(fpath) free(fpath);
return r;
}