/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ /* * Originally written by Alexander Vdolainen */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #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) \"\"\t Command to send to the DSB userspace daemon.\n"); fprintf(stdout, " --unix-socket-path(-u) \t Use 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; }