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
252 lines
6.0 KiB
C
2 years ago
|
/* -*- 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;
|
||
|
}
|