19dba6721SSasha Levin #include <kvm/util.h> 29dba6721SSasha Levin #include <kvm/kvm-cmd.h> 32a24f96dSSasha Levin #include <kvm/builtin-list.h> 49dba6721SSasha Levin #include <kvm/kvm.h> 50725673aSSasha Levin #include <kvm/parse-options.h> 6*4b1addaeSSasha Levin #include <kvm/kvm-ipc.h> 79dba6721SSasha Levin 8076e946eSSasha Levin #include <dirent.h> 99dba6721SSasha Levin #include <stdio.h> 109dba6721SSasha Levin #include <string.h> 119dba6721SSasha Levin #include <signal.h> 121b1577dcSSasha Levin #include <fcntl.h> 131b1577dcSSasha Levin 141b1577dcSSasha Levin #define PROCESS_NAME "kvm" 159dba6721SSasha Levin 16*4b1addaeSSasha Levin struct pid_cmd { 17*4b1addaeSSasha Levin u32 type; 18*4b1addaeSSasha Levin u32 len; 19*4b1addaeSSasha Levin }; 20*4b1addaeSSasha Levin 21076e946eSSasha Levin static bool run; 22076e946eSSasha Levin static bool rootfs; 23076e946eSSasha Levin 240725673aSSasha Levin static const char * const list_usage[] = { 250725673aSSasha Levin "kvm list", 260725673aSSasha Levin NULL 270725673aSSasha Levin }; 280725673aSSasha Levin 290725673aSSasha Levin static const struct option list_options[] = { 30076e946eSSasha Levin OPT_GROUP("General options:"), 31076e946eSSasha Levin OPT_BOOLEAN('i', "run", &run, "List running instances"), 32076e946eSSasha Levin OPT_BOOLEAN('r', "rootfs", &rootfs, "List rootfs instances"), 330725673aSSasha Levin OPT_END() 340725673aSSasha Levin }; 350725673aSSasha Levin 360725673aSSasha Levin void kvm_list_help(void) 370725673aSSasha Levin { 380725673aSSasha Levin usage_with_options(list_usage, list_options); 390725673aSSasha Levin } 400725673aSSasha Levin 41*4b1addaeSSasha Levin static pid_t get_pid(int sock) 42*4b1addaeSSasha Levin { 43*4b1addaeSSasha Levin struct pid_cmd cmd = {KVM_IPC_PID, 0}; 44*4b1addaeSSasha Levin int r; 45*4b1addaeSSasha Levin pid_t pid; 46*4b1addaeSSasha Levin 47*4b1addaeSSasha Levin r = write(sock, &cmd, sizeof(cmd)); 48*4b1addaeSSasha Levin if (r < 0) 49*4b1addaeSSasha Levin return r; 50*4b1addaeSSasha Levin 51*4b1addaeSSasha Levin r = read(sock, &pid, sizeof(pid)); 52*4b1addaeSSasha Levin if (r < 0) 53*4b1addaeSSasha Levin return r; 54*4b1addaeSSasha Levin 55*4b1addaeSSasha Levin return pid; 56*4b1addaeSSasha Levin } 57*4b1addaeSSasha Levin 58*4b1addaeSSasha Levin static int print_guest(const char *name, int sock) 599dba6721SSasha Levin { 601b1577dcSSasha Levin char proc_name[PATH_MAX]; 61ebc49f06SSasha Levin char *comm = NULL; 62ebc49f06SSasha Levin FILE *fd; 63*4b1addaeSSasha Levin pid_t pid = get_pid(sock); 641b1577dcSSasha Levin 65ebc49f06SSasha Levin sprintf(proc_name, "/proc/%d/stat", pid); 66ebc49f06SSasha Levin fd = fopen(proc_name, "r"); 67ebc49f06SSasha Levin if (fd == NULL) 681b1577dcSSasha Levin goto cleanup; 69ebc49f06SSasha Levin if (fscanf(fd, "%*u (%as)", &comm) == 0) 701b1577dcSSasha Levin goto cleanup; 711b1577dcSSasha Levin if (strncmp(comm, PROCESS_NAME, strlen(PROCESS_NAME))) 721b1577dcSSasha Levin goto cleanup; 731b1577dcSSasha Levin 748a09361dSPekka Enberg printf("%5d %s\n", pid, name); 751b1577dcSSasha Levin 76ebc49f06SSasha Levin free(comm); 77ebc49f06SSasha Levin 78ebc49f06SSasha Levin fclose(fd); 791a0ef251SSasha Levin 80886af5f2SLiming Wang return 0; 811b1577dcSSasha Levin 821b1577dcSSasha Levin cleanup: 83ebc49f06SSasha Levin if (fd) 84ebc49f06SSasha Levin fclose(fd); 85ebc49f06SSasha Levin if (comm) 86ebc49f06SSasha Levin free(comm); 87ebc49f06SSasha Levin 88*4b1addaeSSasha Levin kvm__remove_socket(name); 89886af5f2SLiming Wang return 0; 909dba6721SSasha Levin } 919dba6721SSasha Levin 92076e946eSSasha Levin static int kvm_list_running_instances(void) 939dba6721SSasha Levin { 948a09361dSPekka Enberg printf(" PID GUEST\n"); 958a09361dSPekka Enberg 96886af5f2SLiming Wang return kvm__enumerate_instances(print_guest); 979dba6721SSasha Levin } 98076e946eSSasha Levin 99076e946eSSasha Levin static int kvm_list_rootfs(void) 100076e946eSSasha Levin { 101076e946eSSasha Levin char name[PATH_MAX]; 102076e946eSSasha Levin DIR *dir; 103076e946eSSasha Levin struct dirent *dirent; 104076e946eSSasha Levin 1059667701cSPekka Enberg snprintf(name, PATH_MAX, "%s", kvm__get_dir()); 106076e946eSSasha Levin dir = opendir(name); 107076e946eSSasha Levin if (dir == NULL) 108076e946eSSasha Levin return -1; 109076e946eSSasha Levin 110076e946eSSasha Levin printf(" ROOTFS\n"); 111076e946eSSasha Levin 112076e946eSSasha Levin while ((dirent = readdir(dir))) { 113076e946eSSasha Levin if (dirent->d_type == DT_DIR && 114076e946eSSasha Levin strcmp(dirent->d_name, ".") && 115076e946eSSasha Levin strcmp(dirent->d_name, "..")) 116076e946eSSasha Levin printf("%s\n", dirent->d_name); 117076e946eSSasha Levin } 118076e946eSSasha Levin 119076e946eSSasha Levin return 0; 120076e946eSSasha Levin } 121076e946eSSasha Levin 122076e946eSSasha Levin static void parse_setup_options(int argc, const char **argv) 123076e946eSSasha Levin { 124076e946eSSasha Levin while (argc != 0) { 125076e946eSSasha Levin argc = parse_options(argc, argv, list_options, list_usage, 126076e946eSSasha Levin PARSE_OPT_STOP_AT_NON_OPTION); 127076e946eSSasha Levin if (argc != 0) 128076e946eSSasha Levin kvm_list_help(); 129076e946eSSasha Levin } 130076e946eSSasha Levin } 131076e946eSSasha Levin 132076e946eSSasha Levin int kvm_cmd_list(int argc, const char **argv, const char *prefix) 133076e946eSSasha Levin { 134076e946eSSasha Levin int r; 135076e946eSSasha Levin 136076e946eSSasha Levin parse_setup_options(argc, argv); 137076e946eSSasha Levin 138076e946eSSasha Levin if (!run && !rootfs) 139076e946eSSasha Levin kvm_list_help(); 140076e946eSSasha Levin 141076e946eSSasha Levin if (run) { 142076e946eSSasha Levin r = kvm_list_running_instances(); 143076e946eSSasha Levin if (r < 0) 144076e946eSSasha Levin perror("Error listing instances"); 145076e946eSSasha Levin } 146076e946eSSasha Levin 147076e946eSSasha Levin if (rootfs) { 148076e946eSSasha Levin r = kvm_list_rootfs(); 149076e946eSSasha Levin if (r < 0) 150076e946eSSasha Levin perror("Error listing rootfs"); 151076e946eSSasha Levin } 152076e946eSSasha Levin 153076e946eSSasha Levin return 0; 154076e946eSSasha Levin } 155