|  | /* | 
|  | *  Copyright (C) 2000-2013, Parallels, Inc. All rights reserved. | 
|  | * | 
|  | *  This program is free software; you can redistribute it and/or modify | 
|  | *  it under the terms of the GNU General Public License as published by | 
|  | *  the Free Software Foundation; either version 2 of the License, or | 
|  | *  (at your option) any later version. | 
|  | * | 
|  | *  This program is distributed in the hope that it will be useful, | 
|  | *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | *  GNU General Public License for more details. | 
|  | * | 
|  | *  You should have received a copy of the GNU General Public License | 
|  | *  along with this program; if not, write to the Free Software | 
|  | *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <unistd.h> | 
|  | #include <stdlib.h> | 
|  | #include <ctype.h> | 
|  | #include <string.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/socket.h> | 
|  | #include <sys/wait.h> | 
|  | #include <dirent.h> | 
|  | #include <fcntl.h> | 
|  | #include <arpa/inet.h> | 
|  |  | 
|  | #include <getopt.h> | 
|  | #include <fnmatch.h> | 
|  | #include <sys/ioctl.h> | 
|  | #include <errno.h> | 
|  | #include <limits.h> | 
|  | #include <math.h> | 
|  | #include <linux/vzcalluser.h> | 
|  |  | 
|  | #include "vzlist.h" | 
|  | #include "vzconfig.h" | 
|  | #include "fs.h" | 
|  | #include "res.h" | 
|  | #include "logger.h" | 
|  | #include "util.h" | 
|  | #include "types.h" | 
|  | #include "image.h" | 
|  | #include "vzfeatures.h" | 
|  | #include "io.h" | 
|  |  | 
|  | static struct Cveinfo *veinfo = NULL; | 
|  | static int n_veinfo = 0; | 
|  |  | 
|  | static char g_buf[4096] = ""; | 
|  | static char *p_buf = g_buf; | 
|  | static char *e_buf = g_buf + sizeof(g_buf) - 1; | 
|  | static char *host_pattern = NULL; | 
|  | static char *name_pattern = NULL; | 
|  | static char *desc_pattern = NULL; | 
|  | static char *dumpdir = NULL; | 
|  | static int vzctlfd; | 
|  | static struct Cfield_order *g_field_order = NULL; | 
|  | static int is_last_field = 1; | 
|  | static char *default_field_order = "ctid,numproc,status,ip,hostname"; | 
|  | static char *default_nm_field_order = "smart_name,numproc,status,ip,hostname"; | 
|  | static int g_sort_field = 0; | 
|  | static int *g_ve_list = NULL; | 
|  | static int n_ve_list = 0; | 
|  | static int sort_rev = 0; | 
|  | static int show_hdr = 1; | 
|  | static int trim = 1; | 
|  | static int all_ve = 0; | 
|  | static int only_stopped_ve = 0; | 
|  | static long __clk_tck = -1; | 
|  | static int fmt_json = 0; | 
|  |  | 
|  | char logbuf[32]; | 
|  | static int get_run_ve_proc(int); | 
|  | #if HAVE_VZLIST_IOCTL | 
|  | static int get_run_ve_ioctl(int); | 
|  | static inline int get_run_ve(int update) | 
|  | { | 
|  | int ret; | 
|  | ret = get_run_ve_ioctl(update); | 
|  | if (ret) | 
|  | ret = get_run_ve_proc(update); | 
|  | return ret; | 
|  | } | 
|  | #else | 
|  | #define get_run_ve get_run_ve_proc | 
|  | #endif | 
|  |  | 
|  | /* Print functions */ | 
|  | static void print_json_str(const char *s) | 
|  | { | 
|  | if (s) | 
|  | printf("\"%s\"", s); | 
|  | else | 
|  | printf("null"); | 
|  | } | 
|  |  | 
|  | #define PRINT_STR_FIELD_FNAME(funcname, fieldname, length)	\ | 
|  | static void print_ ## funcname(struct Cveinfo *p, int index)	\ | 
|  | {								\ | 
|  | int r;							\ | 
|  | char *str = "-";					\ | 
|  | \ | 
|  | if (fmt_json)						\ | 
|  | return print_json_str(p->fieldname);		\ | 
|  | \ | 
|  | if (p->fieldname != NULL)				\ | 
|  | str = p->fieldname;				\ | 
|  | r = snprintf(p_buf, e_buf - p_buf,			\ | 
|  | "%" #length "s", str);				\ | 
|  | if (!is_last_field)					\ | 
|  | r = abs(length);				\ | 
|  | p_buf += r;						\ | 
|  | } | 
|  |  | 
|  | #define PRINT_STR_FIELD(name, length)				\ | 
|  | PRINT_STR_FIELD_FNAME(name, name, length) | 
|  |  | 
|  | PRINT_STR_FIELD(private, -32) | 
|  | PRINT_STR_FIELD(root, -32) | 
|  | PRINT_STR_FIELD(mount_opts, -16) | 
|  | PRINT_STR_FIELD(origin_sample, -32) | 
|  | PRINT_STR_FIELD(hostname, -32) | 
|  | PRINT_STR_FIELD(name, -32) | 
|  | PRINT_STR_FIELD(description, -32) | 
|  | PRINT_STR_FIELD(ostemplate, -32) | 
|  | PRINT_STR_FIELD_FNAME(name_short, name, 10) | 
|  |  | 
|  | static void print_json_list(const char *list) | 
|  | { | 
|  | static const char spc[] = " \t"; | 
|  | int first_item = 1; | 
|  | const char *item; | 
|  | const char *endp; | 
|  |  | 
|  | if (!list) { | 
|  | printf("[]"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | printf("["); | 
|  | item = list; | 
|  | endp = list + strlen(list); | 
|  | while (item < endp) { | 
|  | int toklen; | 
|  |  | 
|  | item += strspn(item, spc); | 
|  | if (item >= endp) | 
|  | break; | 
|  |  | 
|  | toklen = strcspn(item, spc); | 
|  | printf("%s\"%.*s\"", first_item ? "" : ", ", toklen, item); | 
|  | first_item = 0; | 
|  | item += toklen; | 
|  | } | 
|  | printf("]"); | 
|  | } | 
|  |  | 
|  | static void print_strlist(char *list) | 
|  | { | 
|  | int r; | 
|  | char *str = "-"; | 
|  | char *ch; | 
|  |  | 
|  | if (fmt_json) | 
|  | return print_json_list(list); | 
|  |  | 
|  | if (list != NULL) | 
|  | str = list; | 
|  | if (!is_last_field) | 
|  | { | 
|  | /* Fixme: dont destroy original string */ | 
|  | if ((ch = strchr(str, ' ')) != NULL) | 
|  | *ch = 0; | 
|  | } | 
|  | r = snprintf(p_buf, e_buf - p_buf, "%-15s", str); | 
|  | if (!is_last_field) | 
|  | r = 15; | 
|  | p_buf += r; | 
|  | } | 
|  |  | 
|  | static void print_ip(struct Cveinfo *p, int index) | 
|  | { | 
|  | print_strlist(p->ip); | 
|  | } | 
|  |  | 
|  | static void print_nameserver(struct Cveinfo *p, int index) | 
|  | { | 
|  | print_strlist(p->nameserver); | 
|  | } | 
|  |  | 
|  | static void print_searchdomain(struct Cveinfo *p, int index) | 
|  | { | 
|  | print_strlist(p->searchdomain); | 
|  | } | 
|  |  | 
|  | static void print_veid(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (fmt_json) | 
|  | printf("%d", p->veid); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%10d", p->veid); | 
|  | } | 
|  |  | 
|  | static void print_smart_name(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (p->name != NULL) | 
|  | print_name_short(p, index); | 
|  | else | 
|  | print_veid(p, index); | 
|  | } | 
|  |  | 
|  | static void print_status(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (fmt_json) | 
|  | print_json_str(ve_status[p->status]); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%-9s", ve_status[p->status]); | 
|  | } | 
|  |  | 
|  | static void print_laverage(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (p->cpustat == NULL) { | 
|  | if (fmt_json) | 
|  | printf("null"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%14s", "-"); | 
|  | } | 
|  | else { | 
|  | if (fmt_json) | 
|  | printf("[%1.2f, %1.2f, %1.2f]", | 
|  | p->cpustat->la[0], | 
|  | p->cpustat->la[1], | 
|  | p->cpustat->la[2]); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%1.2f/%1.2f/%1.2f", | 
|  | p->cpustat->la[0], | 
|  | p->cpustat->la[1], | 
|  | p->cpustat->la[2]); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void print_uptime(struct Cveinfo *p, int index) | 
|  | { | 
|  |  | 
|  | if (fmt_json) { | 
|  | printf("%.3f", p->cpustat ? p->cpustat->uptime : 0.); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (p->cpustat == NULL) | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%15s", "-"); | 
|  | else | 
|  | { | 
|  | unsigned int days, hours, min, secs; | 
|  |  | 
|  | days  = (unsigned int)(p->cpustat->uptime / (60 * 60 * 24)); | 
|  | min = (unsigned int)(p->cpustat->uptime / 60); | 
|  | hours = min / 60; | 
|  | hours = hours % 24; | 
|  | min = min % 60; | 
|  | secs = (unsigned int)(p->cpustat->uptime - | 
|  | (60ull * min + 60ull * 60 * hours + | 
|  | 60ull * 60 * 24 * days)); | 
|  |  | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%.3dd%.2dh:%.2dm:%.2ds", | 
|  | days, hours, min, secs); | 
|  | } | 
|  | } | 
|  |  | 
|  | #define PRINT_CPU(name)						\ | 
|  | static void print_cpu ## name(struct Cveinfo *p, int index)	\ | 
|  | {								\ | 
|  | if (p->cpu == NULL) {					\ | 
|  | if (fmt_json)					\ | 
|  | printf("null");				\ | 
|  | else						\ | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf,	\ | 
|  | "%7s", "-");		\ | 
|  | }							\ | 
|  | else {							\ | 
|  | if (fmt_json)					\ | 
|  | printf("%lu", p->cpu->name[index]);	\ | 
|  | else						\ | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf,	\ | 
|  | "%7lu", p->cpu->name[index]);	\ | 
|  | }							\ | 
|  | } | 
|  |  | 
|  | PRINT_CPU(limit) | 
|  | PRINT_CPU(units) | 
|  |  | 
|  | #define PRINT_IO(name, fmt, min)				\ | 
|  | static void print_io ## name(struct Cveinfo *p, int index)	\ | 
|  | {								\ | 
|  | int i = p->io.io ## name;				\ | 
|  | \ | 
|  | if (fmt_json) {						\ | 
|  | printf("%d", (i < 0) ? 0 : i);			\ | 
|  | return;						\ | 
|  | }							\ | 
|  | \ | 
|  | if (i < min)						\ | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf,		\ | 
|  | fmt "s", "-");			\ | 
|  | else							\ | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf,		\ | 
|  | fmt "d", i);			\ | 
|  | } | 
|  |  | 
|  | PRINT_IO(prio, "%3", 0) | 
|  | PRINT_IO(limit, "%10", 1) | 
|  | PRINT_IO(pslimit, "%4", 1) | 
|  | #undef PRINT_IO | 
|  |  | 
|  | static void print_bool(const char *fmt, int val) | 
|  | { | 
|  | if (fmt_json) | 
|  | printf(val ? "true" : "false"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf-p_buf, | 
|  | fmt, val ? "yes" : "no"); | 
|  | } | 
|  |  | 
|  | static void print_onboot(struct Cveinfo *p, int index) | 
|  | { | 
|  | /* ONBOOT value is NONE (0), YES (1) or NO (2) */ | 
|  | if (p->onboot) | 
|  | return print_bool("%6s", p->onboot == YES); | 
|  |  | 
|  | if (fmt_json) | 
|  | printf("null"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf-p_buf, "%6s", "-"); | 
|  | } | 
|  |  | 
|  | static void print_bootorder(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (p->bootorder == NULL) { | 
|  | if (fmt_json) | 
|  | printf("null"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf-p_buf, | 
|  | "%10s", "-"); | 
|  | } | 
|  | else { | 
|  | if (fmt_json) | 
|  | printf("%lu", p->bootorder[index]); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf-p_buf, | 
|  | "%10lu", p->bootorder[index]); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void print_cpunum(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (fmt_json) { | 
|  | printf("%d", p->cpunum < 0 ? 0 : p->cpunum); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (p->cpunum <= 0) | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%5s", "-"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%5d", p->cpunum); | 
|  | } | 
|  |  | 
|  | static const char *layout2str(int layout) | 
|  | { | 
|  | switch (layout) | 
|  | { | 
|  | case VE_LAYOUT_SIMFS: | 
|  | return "simfs"; | 
|  | case VE_LAYOUT_PLOOP: | 
|  | return "ploop"; | 
|  | } | 
|  | return "???"; | 
|  | } | 
|  |  | 
|  | static void print_layout(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (fmt_json) | 
|  | print_json_str(layout2str(p->layout)); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | "%-6s",	layout2str(p->layout)); | 
|  | } | 
|  |  | 
|  | static void print_features(struct Cveinfo *p, int index) | 
|  | { | 
|  | int r; | 
|  | char str[64]="-"; | 
|  |  | 
|  | if (fmt_json) | 
|  | return print_json_features(p->features_mask, | 
|  | p->features_known); | 
|  |  | 
|  | features_mask2str(p->features_mask, p->features_known, | 
|  | ",", str, sizeof(str)); | 
|  | r = snprintf(p_buf, e_buf - p_buf, "%-15s", str); | 
|  | if (!is_last_field) | 
|  | r = 15; | 
|  | p_buf += r; | 
|  | } | 
|  |  | 
|  | static void print_ubc(struct Cveinfo *p, size_t res_off, int index) | 
|  | { | 
|  | int running = p->status == VE_RUNNING; | 
|  | unsigned long *res = p->ubc ? | 
|  | (unsigned long *)(p->ubc) + res_off : NULL; | 
|  |  | 
|  | if (fmt_json) { | 
|  | if (res) { | 
|  | printf("{\n" | 
|  | "      \"held\": %lu,\n" | 
|  | "      \"maxheld\": %lu,\n" | 
|  | "      \"barrier\": %lu,\n" | 
|  | "      \"limit\": %lu,\n" | 
|  | "      \"failcnt\": %lu\n" | 
|  | "    }", | 
|  | running ? res[0] : 0, | 
|  | running ? res[1] : 0, | 
|  | res[2], res[3], | 
|  | running ? res[4] : 0); | 
|  | } else | 
|  | printf("null"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!res || (!running && (index == 0 || index == 1 || index == 4))) | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, "%10s", "-"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, "%10lu", | 
|  | res[index]); | 
|  | } | 
|  |  | 
|  | #ifndef offsetof | 
|  | # define offsetof(TYPE, MEMBER)  __builtin_offsetof (TYPE, MEMBER) | 
|  | #endif | 
|  |  | 
|  | #define PRINT_UBC(name)							\ | 
|  | static void print_ubc_ ## name(struct Cveinfo *p, int index)		\ | 
|  | {									\ | 
|  | print_ubc(p, offsetof(struct Cubc, name) /			\ | 
|  | sizeof(unsigned long), index);			\ | 
|  | } | 
|  |  | 
|  | FOR_ALL_UBC(PRINT_UBC) | 
|  |  | 
|  | static void print_vswap(struct Cveinfo *p, int index) | 
|  | { | 
|  | /* Same conditions as used in is_vswap_config() */ | 
|  | int vswap = (p->ubc != NULL) && | 
|  | (p->ubc->physpages[3] != LONG_MAX) && | 
|  | (p->ubc->physpages[3] != INT_MAX); | 
|  |  | 
|  | print_bool("%5s", vswap); | 
|  | } | 
|  |  | 
|  | static void print_disabled(struct Cveinfo *p, int index) | 
|  | { | 
|  | print_bool("%6s", p->disabled == YES); | 
|  | } | 
|  |  | 
|  | static void print_dq(struct Cveinfo *p, size_t res_off, int index) | 
|  | { | 
|  | unsigned long *res = p->quota ? | 
|  | (unsigned long *)(p->quota) + res_off : NULL; | 
|  |  | 
|  | if (fmt_json) { | 
|  | if (res) { | 
|  | printf("{\n" | 
|  | "      \"usage\": %lu,\n" | 
|  | "      \"softlimit\": %lu,\n" | 
|  | "      \"hardlimit\": %lu\n" | 
|  | "    }", | 
|  | res[0], res[1], res[2]); | 
|  | } else | 
|  | printf("null"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!res || (index == 0 && res[index] == 0)) | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, "%10s", "-"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, "%10lu", | 
|  | res[index]); | 
|  | } | 
|  |  | 
|  | #define PRINT_DQ(name)							\ | 
|  | static void print_ ## name(struct Cveinfo *p, int index)		\ | 
|  | {									\ | 
|  | print_dq(p, offsetof(struct Cquota, name) /			\ | 
|  | sizeof(unsigned long), index);			\ | 
|  | } | 
|  |  | 
|  | PRINT_DQ(diskspace) | 
|  | PRINT_DQ(diskinodes) | 
|  |  | 
|  | static void print_vm_overcommit(struct Cveinfo *p, int index) | 
|  | { | 
|  | if (fmt_json) { | 
|  | printf("%g", p->vm_overcommit); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (p->vm_overcommit == 0) | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, "%6s", "-"); | 
|  | else | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, "%6g", | 
|  | p->vm_overcommit); | 
|  | } | 
|  |  | 
|  | /* Sort functions */ | 
|  |  | 
|  | static inline int check_empty_param(const void *val1, const void *val2) | 
|  | { | 
|  | if (val1 == NULL && val2 == NULL) | 
|  | return 0; | 
|  | else if (val1 == NULL) | 
|  | return -1; | 
|  | else if (val2 == NULL) | 
|  | return 1; | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static int none_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int laverage_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | const struct Ccpustat *st1 = ((const struct Cveinfo *)val1)->cpustat; | 
|  | const struct Ccpustat *st2 = ((const struct Cveinfo *)val2)->cpustat; | 
|  | int res; | 
|  |  | 
|  | if ((res = check_empty_param(st1, st2)) != 2) | 
|  | return res; | 
|  | res = (st1->la[0] - st2->la[0]) * 100; | 
|  | if (res != 0) | 
|  | return res; | 
|  | res = (st1->la[1] - st2->la[1]) * 100; | 
|  | if (res != 0) | 
|  | return res; | 
|  | return (st1->la[2] - st2->la[2]) * 100; | 
|  | } | 
|  |  | 
|  | static int uptime_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | struct Ccpustat *st1 = ((const struct Cveinfo *)val1)->cpustat; | 
|  | struct Ccpustat *st2 = ((const struct Cveinfo *)val2)->cpustat; | 
|  | int res; | 
|  |  | 
|  | if ((res = check_empty_param(st1, st2)) != 2) | 
|  | return res; | 
|  | return (st2->uptime - st1->uptime); | 
|  | } | 
|  |  | 
|  | static int id_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | int ret; | 
|  | ret = (((const struct Cveinfo*)val1)->veid > | 
|  | ((const struct Cveinfo*)val2)->veid); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int status_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | int res; | 
|  | res = ((const struct Cveinfo*)val1)->status - | 
|  | ((const struct Cveinfo*)val2)->status; | 
|  | if (!res) | 
|  | res = id_sort_fn(val1, val2); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | static int bootorder_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | int ret; | 
|  | unsigned long *r1 = ((const struct Cveinfo*)val1)->bootorder; | 
|  | unsigned long *r2 = ((const struct Cveinfo*)val2)->bootorder; | 
|  |  | 
|  | ret = check_empty_param(r1, r2); | 
|  | switch (ret) { | 
|  | case 0: /* both NULL */ | 
|  | return !id_sort_fn(val1, val2); | 
|  | case 2: /* both not NULL */ | 
|  | break; | 
|  | default: /* one is NULL, other is not */ | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (*r1 == *r2) | 
|  | return !id_sort_fn(val1, val2); | 
|  |  | 
|  | return (*r1 > *r2); | 
|  | } | 
|  |  | 
|  | #define IO_SORT_FN(name)						\ | 
|  | static int io ## name ## _sort_fn(const void *val1, const void *val2)	\ | 
|  | {									\ | 
|  | return ((const struct Cveinfo *)val1)->io.io ## name >		\ | 
|  | ((const struct Cveinfo *)val2)->io.io ## name;		\ | 
|  | } | 
|  |  | 
|  | IO_SORT_FN(prio) | 
|  | IO_SORT_FN(limit) | 
|  | IO_SORT_FN(pslimit) | 
|  | #undef IO_SORT_FN | 
|  |  | 
|  | static int cpunum_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | return ((const struct Cveinfo *)val1)->cpunum > | 
|  | ((const struct Cveinfo *)val2)->cpunum; | 
|  | } | 
|  |  | 
|  | static int layout_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | return ((const struct Cveinfo *)val1)->layout > | 
|  | ((const struct Cveinfo *)val2)->layout; | 
|  | } | 
|  |  | 
|  | #define SORT_STR_FN(name)						\ | 
|  | static int name ## _sort_fn(const void *val1, const void *val2)		\ | 
|  | {									\ | 
|  | const char *h1 = ((const struct Cveinfo*)val1)->name;		\ | 
|  | const char *h2 = ((const struct Cveinfo*)val2)->name;		\ | 
|  | int ret;							\ | 
|  | if ((ret = check_empty_param(h1, h2)) == 2)			\ | 
|  | ret = strcmp(h1, h2);					\ | 
|  | return ret;							\ | 
|  | } | 
|  |  | 
|  | SORT_STR_FN(private) | 
|  | SORT_STR_FN(root) | 
|  | SORT_STR_FN(mount_opts) | 
|  | SORT_STR_FN(origin_sample) | 
|  | SORT_STR_FN(hostname) | 
|  | SORT_STR_FN(name) | 
|  | SORT_STR_FN(description) | 
|  | SORT_STR_FN(ostemplate) | 
|  | SORT_STR_FN(ip) | 
|  | SORT_STR_FN(nameserver) | 
|  | SORT_STR_FN(searchdomain) | 
|  |  | 
|  | #define SORT_UL_RES(fn, res, name, index)				\ | 
|  | static int fn(const void *val1, const void *val2)			\ | 
|  | {									\ | 
|  | const struct C ## res *r1 = ((const struct Cveinfo *)val1)->res;\ | 
|  | const struct C ## res *r2 = ((const struct Cveinfo *)val2)->res;\ | 
|  | int ret;							\ | 
|  | if ((ret = check_empty_param(r1, r2)) == 2)			\ | 
|  | ret = r1->name[index] > r2->name[index];		\ | 
|  | return ret;							\ | 
|  | } | 
|  |  | 
|  | #define SORT_UBC(res)							\ | 
|  | SORT_UL_RES(res ## _h_sort_fn, ubc, res, 0)				\ | 
|  | SORT_UL_RES(res ## _m_sort_fn, ubc, res, 1)				\ | 
|  | SORT_UL_RES(res ## _l_sort_fn, ubc, res, 2)				\ | 
|  | SORT_UL_RES(res ## _b_sort_fn, ubc, res, 3)				\ | 
|  | SORT_UL_RES(res ## _f_sort_fn, ubc, res, 4) | 
|  |  | 
|  | FOR_ALL_UBC(SORT_UBC) | 
|  |  | 
|  | #define SORT_DQ(res)							\ | 
|  | SORT_UL_RES(res ## _u_sort_fn, quota, res, 0)				\ | 
|  | SORT_UL_RES(res ## _s_sort_fn, quota, res, 1)				\ | 
|  | SORT_UL_RES(res ## _h_sort_fn, quota, res, 2) | 
|  |  | 
|  | SORT_DQ(diskspace) | 
|  | SORT_DQ(diskinodes) | 
|  |  | 
|  | SORT_UL_RES(cpulimit_sort_fn, cpu, limit, 0) | 
|  | SORT_UL_RES(cpuunits_sort_fn, cpu, units, 0) | 
|  |  | 
|  | #define UBC_FIELD(name, header) \ | 
|  | {#name,      #header,      "%10s", 0, RES_UBC, print_ubc_ ## name, name ## _h_sort_fn},	\ | 
|  | {#name ".m", #header ".M", "%10s", 1, RES_UBC, print_ubc_ ## name, name ## _m_sort_fn},	\ | 
|  | {#name ".b", #header ".B", "%10s", 2, RES_UBC, print_ubc_ ## name, name ## _b_sort_fn},	\ | 
|  | {#name ".l", #header ".L", "%10s", 3, RES_UBC, print_ubc_ ## name, name ## _l_sort_fn},	\ | 
|  | {#name ".f", #header ".F", "%10s", 4, RES_UBC, print_ubc_ ## name, name ## _f_sort_fn} | 
|  |  | 
|  | static struct Cfield field_names[] = | 
|  | { | 
|  | /* ctid should have index 0 */ | 
|  | {"ctid", "CTID", "%10s", 0, RES_NONE, print_veid, id_sort_fn}, | 
|  | /* veid is for backward compatibility -- will be removed later */ | 
|  | {"veid", "CTID", "%10s", 0, RES_NONE, print_veid, id_sort_fn}, | 
|  | /* vpsid is for backward compatibility -- will be removed later */ | 
|  | {"vpsid", "CTID", "%10s", 0, RES_NONE, print_veid, id_sort_fn}, | 
|  |  | 
|  | {"private", "PRIVATE", "%-32s", 0, RES_NONE, print_private, private_sort_fn}, | 
|  | {"root", "ROOT", "%-32s", 0, RES_NONE, print_root, root_sort_fn}, | 
|  | {"mount_opts", "MOUNT_OPTS", "%-16s", 0, RES_NONE, print_mount_opts, mount_opts_sort_fn}, | 
|  | {"origin_sample", "ORIGIN_SAMPLE", "%32s", 0, RES_NONE, print_origin_sample, origin_sample_sort_fn}, | 
|  | {"hostname", "HOSTNAME", "%-32s", 0, RES_HOSTNAME, print_hostname, hostname_sort_fn}, | 
|  | {"name", "NAME", "%-32s", 0, RES_NONE, print_name, name_sort_fn}, | 
|  | {"smart_name", "SMARTNAME", "%10s", 0, RES_NONE, print_smart_name, name_sort_fn}, | 
|  | {"description", "DESCRIPTION", "%-32s", 0, RES_NONE, print_description, description_sort_fn }, | 
|  | {"ostemplate", "OSTEMPLATE", "%-32s", 0, RES_NONE, print_ostemplate, ostemplate_sort_fn }, | 
|  | {"ip", "IP_ADDR", "%-15s", 0, RES_IP, print_ip, ip_sort_fn}, | 
|  | {"nameserver", "NAMESERVER", "%-15s", 0, RES_NONE, print_nameserver, nameserver_sort_fn}, | 
|  | {"searchdomain", "SEARCHDOMAIN", "%-15s", 0, RES_NONE, print_searchdomain, searchdomain_sort_fn}, | 
|  | {"status", "STATUS", "%-9s", 0, RES_STATUS, print_status, status_sort_fn}, | 
|  | /*	UBC	*/ | 
|  | UBC_FIELD(kmemsize, KMEMSIZE), | 
|  | UBC_FIELD(lockedpages, LOCKEDP), | 
|  | UBC_FIELD(privvmpages, PRIVVMP), | 
|  | UBC_FIELD(shmpages, SHMP), | 
|  | UBC_FIELD(numproc, NPROC), | 
|  | UBC_FIELD(physpages, PHYSP), | 
|  | UBC_FIELD(vmguarpages, VMGUARP), | 
|  | UBC_FIELD(oomguarpages, OOMGUARP), | 
|  | UBC_FIELD(numtcpsock, NTCPSOCK), | 
|  | UBC_FIELD(numflock, NFLOCK), | 
|  | UBC_FIELD(numpty, NPTY), | 
|  | UBC_FIELD(numsiginfo, NSIGINFO), | 
|  | UBC_FIELD(tcpsndbuf, TCPSNDB), | 
|  | UBC_FIELD(tcprcvbuf, TCPRCVB), | 
|  | UBC_FIELD(othersockbuf, OTHSOCKB), | 
|  | UBC_FIELD(dgramrcvbuf, DGRAMRB), | 
|  | UBC_FIELD(numothersock, NOTHSOCK), | 
|  | UBC_FIELD(dcachesize, DCACHESZ), | 
|  | UBC_FIELD(numfile, NFILE), | 
|  | UBC_FIELD(numiptent, NIPTENT), | 
|  | UBC_FIELD(swappages, SWAPP), | 
|  |  | 
|  | {"diskspace", "DSPACE", "%10s", 0, RES_QUOTA, print_diskspace, diskspace_u_sort_fn}, | 
|  | {"diskspace.s", "DSPACE.S", "%10s", 1, RES_QUOTA, print_diskspace, diskspace_s_sort_fn}, | 
|  | {"diskspace.h", "DSPACE.H", "%10s", 2, RES_QUOTA, print_diskspace, diskspace_h_sort_fn}, | 
|  |  | 
|  | {"diskinodes", "DINODES", "%10s", 0, RES_QUOTA, print_diskinodes, diskinodes_u_sort_fn}, | 
|  | {"diskinodes.s", "DINODES.S", "%10s", 1, RES_QUOTA, print_diskinodes, diskinodes_s_sort_fn}, | 
|  | {"diskinodes.h", "DINODES.H", "%10s", 2, RES_QUOTA, print_diskinodes, diskinodes_h_sort_fn}, | 
|  |  | 
|  | {"laverage", "LAVERAGE", "%14s", 0, RES_CPUSTAT, print_laverage, laverage_sort_fn}, | 
|  | {"uptime", "UPTIME", "%15s", 0, RES_CPUSTAT, print_uptime, uptime_sort_fn}, | 
|  |  | 
|  | {"cpulimit", "CPULIM", "%7s", 0, RES_CPU, print_cpulimit, cpulimit_sort_fn}, | 
|  | {"cpuunits", "CPUUNI", "%7s", 0, RES_CPU, print_cpuunits, cpuunits_sort_fn}, | 
|  | {"cpus", "CPUS", "%5s", 0, RES_CPUNUM, print_cpunum, cpunum_sort_fn}, | 
|  |  | 
|  | {"ioprio", "IOP", "%3s", 0, RES_NONE, print_ioprio, ioprio_sort_fn}, | 
|  | {"iolimit", "IOLIMIT", "%10s", 0, RES_IO, print_iolimit, iolimit_sort_fn}, | 
|  | {"iopslimit", "IOPS", "%4s", 0, RES_IO, print_iopslimit, iopslimit_sort_fn}, | 
|  |  | 
|  | {"onboot", "ONBOOT", "%6s", 0, RES_NONE, print_onboot, none_sort_fn}, | 
|  | {"bootorder", "BOOTORDER", "%10s", 0, RES_NONE, | 
|  | print_bootorder, bootorder_sort_fn}, | 
|  | {"layout", "LAYOUT", "%6s", 0, RES_NONE, print_layout, layout_sort_fn}, | 
|  | {"features", "FEATURES", "%-15s", 0, RES_NONE, print_features, none_sort_fn}, | 
|  | {"vswap", "VSWAP", "%5s", 0, RES_NONE, print_vswap, none_sort_fn}, | 
|  | {"disabled", "DISABL", "%6s", 0, RES_NONE, print_disabled, none_sort_fn}, | 
|  | {"vm_overcommit", "VM_OVC", "%6s", 0, RES_NONE, | 
|  | print_vm_overcommit, none_sort_fn}, | 
|  | }; | 
|  |  | 
|  | static void *x_malloc(int size) | 
|  | { | 
|  | void *p; | 
|  | if ((p = malloc(size)) == NULL) { | 
|  | fprintf(stderr, "Error: unable to allocate %d bytes\n", size); | 
|  | exit(1); | 
|  | } | 
|  | return p; | 
|  | } | 
|  |  | 
|  | static void *x_realloc(void *ptr, int size) | 
|  | { | 
|  | void *tmp; | 
|  |  | 
|  | if ((tmp = realloc(ptr, size)) == NULL) { | 
|  | fprintf(stderr, "Error: unable to allocate %d bytes\n", size); | 
|  | exit(1); | 
|  | } | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | static void usage() | 
|  | { | 
|  | printf( | 
|  | "Usage:	vzlist [-a | -S] [-n] [-H] [-o field[,field...] | -1] [-s [-]field]\n" | 
|  | "	       [-h pattern] [-N pattern] [-d pattern] [CTID [CTID ...]]\n" | 
|  | "	vzlist -L | --list\n" | 
|  | "\n" | 
|  | "Options:\n" | 
|  | "	-a, --all		list all containers\n" | 
|  | "	-S, --stopped		list stopped containers\n" | 
|  | "	-n, --name		display containers' names\n" | 
|  | "	-H, --no-header		suppress columns header\n" | 
|  | "	-t, --no-trim		do not trim long values\n" | 
|  | "	-j, --json		output in JSON format\n" | 
|  | "	-o, --output		output only specified fields\n" | 
|  | "	-1			synonym for -H -octid\n" | 
|  | "	-s, --sort		sort by the specified field\n" | 
|  | "				('-field' to reverse sort order)\n" | 
|  | "	-h, --hostname		filter CTs by hostname pattern\n" | 
|  | "	-N, --name_filter	filter CTs by name pattern\n" | 
|  | "	-d, --description	filter CTs by description pattern\n" | 
|  | "	-L, --list		get possible field names\n" | 
|  | ); | 
|  | } | 
|  |  | 
|  | static int id_search_fn(const void* val1, const void* val2) | 
|  | { | 
|  | return (*(const int *)val1 - ((const struct Cveinfo*)val2)->veid); | 
|  | } | 
|  |  | 
|  | static int veid_search_fn(const void* val1, const void* val2) | 
|  | { | 
|  | return (*(const int *)val1 - *(const int *)val2); | 
|  | } | 
|  |  | 
|  | static char* trim_eol_space(char *sp, char *ep) | 
|  | { | 
|  | /*	if (ep == NULL) | 
|  | ep = sp + strlen(sp); */ | 
|  |  | 
|  | ep--; | 
|  | while (isspace(*ep) && ep >= sp) *ep-- = '\0'; | 
|  |  | 
|  | return sp; | 
|  | } | 
|  |  | 
|  | static void print_hdr() | 
|  | { | 
|  | struct Cfield_order *p; | 
|  | int f; | 
|  |  | 
|  | for (p = g_field_order; p != NULL; p = p->next) { | 
|  | f = p->order; | 
|  | p_buf += snprintf(p_buf, e_buf - p_buf, | 
|  | field_names[f].hdr_fmt, field_names[f].hdr); | 
|  | if (p_buf >= e_buf) | 
|  | break; | 
|  | if (p->next != NULL) | 
|  | *p_buf++ = ' '; | 
|  | } | 
|  | printf("%s\n", trim_eol_space(g_buf, p_buf)); | 
|  | g_buf[0] = 0; | 
|  | p_buf = g_buf; | 
|  | } | 
|  |  | 
|  | /* | 
|  | 1 - match | 
|  | 0 - do not match | 
|  | */ | 
|  | static inline int check_pattern(char *str, char *pat) | 
|  | { | 
|  | if (pat == NULL) | 
|  | return 1; | 
|  | if (str == NULL) | 
|  | return 0; | 
|  | return !fnmatch(pat, str, 0); | 
|  | } | 
|  |  | 
|  | static void filter_by_hostname() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (!check_pattern(veinfo[i].hostname, host_pattern)) | 
|  | veinfo[i].hide = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void filter_by_name() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (!check_pattern(veinfo[i].name, name_pattern)) | 
|  | veinfo[i].hide = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void filter_by_description() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (!check_pattern(veinfo[i].description, desc_pattern)) | 
|  | veinfo[i].hide = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void print_one_ve(struct Cveinfo *ve) | 
|  | { | 
|  | struct Cfield_order *p; | 
|  | int f; | 
|  |  | 
|  | if (trim) | 
|  | is_last_field = 0; | 
|  |  | 
|  | for (p = g_field_order; p != NULL; p = p->next) { | 
|  | f = p->order; | 
|  | if (p->next == NULL) | 
|  | is_last_field = 1; | 
|  | field_names[f].print_fn(ve, field_names[f].index); | 
|  | if (p_buf >= e_buf) | 
|  | break; | 
|  | if (p->next != NULL) | 
|  | *p_buf++ = ' '; | 
|  | } | 
|  |  | 
|  | printf("%s\n", trim_eol_space(g_buf, p_buf)); | 
|  | g_buf[0] = 0; | 
|  | p_buf = g_buf; | 
|  | } | 
|  |  | 
|  | static void print_field_json(struct Cveinfo *ve, int fi) | 
|  | { | 
|  | static struct Cveinfo *prev_ve = NULL; | 
|  |  | 
|  | printf("%s\n    \"%s\": ", prev_ve == ve ? "," : "", | 
|  | field_names[fi].name); | 
|  | field_names[fi].print_fn(ve, field_names[fi].index); | 
|  | prev_ve = ve; | 
|  | } | 
|  |  | 
|  | static void print_one_ve_json(struct Cveinfo *ve) | 
|  | { | 
|  | static int first_entry = 1; | 
|  |  | 
|  | printf("%s\n  {", first_entry ? "" : ","); | 
|  | first_entry = 0; | 
|  | if (g_field_order) { | 
|  | struct Cfield_order *p; | 
|  | for (p = g_field_order; p != NULL; p = p->next) | 
|  | print_field_json(ve, p->order); | 
|  | } else { | 
|  | unsigned long i; | 
|  | for (i = 0; i < ARRAY_SIZE(field_names); i++) | 
|  | if (!field_names[i].index) | 
|  | print_field_json(ve, i); | 
|  | } | 
|  | printf("\n  }"); | 
|  | } | 
|  | static void print_ve() | 
|  | { | 
|  | int i, idx; | 
|  |  | 
|  | /* If sort order != veid (already sorted by) */ | 
|  | if (g_sort_field) { | 
|  | qsort(veinfo, n_veinfo, sizeof(struct Cveinfo), | 
|  | field_names[g_sort_field].sort_fn); | 
|  | } | 
|  | if (!(!show_hdr || fmt_json)) | 
|  | print_hdr(); | 
|  | if (fmt_json) | 
|  | printf("["); | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (sort_rev) | 
|  | idx = n_veinfo - i - 1; | 
|  | else | 
|  | idx = i; | 
|  | if (veinfo[idx].hide) | 
|  | continue; | 
|  | if (only_stopped_ve && veinfo[idx].status == VE_RUNNING) | 
|  | continue; | 
|  | if (fmt_json) | 
|  | print_one_ve_json(&veinfo[idx]); | 
|  | else | 
|  | print_one_ve(&veinfo[idx]); | 
|  | } | 
|  | if (fmt_json) | 
|  | printf("\n]\n"); | 
|  | } | 
|  |  | 
|  | static void add_elem(struct Cveinfo *ve) | 
|  | { | 
|  | veinfo = (struct Cveinfo *)x_realloc(veinfo, | 
|  | sizeof(struct Cveinfo) * ++n_veinfo); | 
|  | ve->cpunum = -1; | 
|  | memcpy(&veinfo[n_veinfo - 1], ve, sizeof(struct Cveinfo)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | static struct Cveinfo *find_ve(int veid) | 
|  | { | 
|  | return (struct Cveinfo *) bsearch(&veid, veinfo, n_veinfo, | 
|  | sizeof(struct Cveinfo), id_search_fn); | 
|  | } | 
|  |  | 
|  | static void update_ve(int veid, char *ip, int status) | 
|  | { | 
|  | struct Cveinfo *tmp, ve; | 
|  |  | 
|  | tmp = find_ve(veid); | 
|  | if (tmp == NULL) { | 
|  | memset(&ve, 0, sizeof(struct Cveinfo)); | 
|  | ve.veid = veid; | 
|  | ve.status = status; | 
|  | ve.ip = ip; | 
|  | add_elem(&ve); | 
|  | qsort(veinfo, n_veinfo, sizeof(struct Cveinfo), id_sort_fn); | 
|  | return; | 
|  | } else { | 
|  | if (tmp->ip == NULL) | 
|  | tmp->ip = ip; | 
|  | else | 
|  | free(ip); | 
|  | tmp->status = status; | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | static void update_ubc(int veid, const struct Cubc *ubc) | 
|  | { | 
|  | struct Cveinfo *tmp; | 
|  |  | 
|  | if ((tmp = find_ve(veid)) != NULL) { | 
|  | if (tmp->status != VE_RUNNING) | 
|  | return; | 
|  | if (tmp->ubc == NULL) | 
|  | tmp->ubc = x_malloc(sizeof(*ubc)); | 
|  | memcpy(tmp->ubc, ubc, sizeof(*ubc)); | 
|  | } | 
|  | return ; | 
|  | } | 
|  |  | 
|  | static void update_quota(int veid, struct Cquota *quota) | 
|  | { | 
|  | struct Cveinfo *tmp; | 
|  |  | 
|  | if ((tmp = find_ve(veid)) == NULL) | 
|  | return; | 
|  | tmp->quota = x_malloc(sizeof(*quota)); | 
|  | memcpy(tmp->quota, quota, sizeof(*quota)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | static void update_cpu(int veid, unsigned long limit, unsigned long units) | 
|  | { | 
|  | struct Cveinfo *tmp; | 
|  | struct Ccpu *cpu; | 
|  |  | 
|  | if ((tmp = find_ve(veid)) == NULL) | 
|  | return; | 
|  | cpu = x_malloc(sizeof(*cpu)); | 
|  | cpu->limit[0] = limit; | 
|  | cpu->units[0] = units; | 
|  | tmp->cpu = cpu; | 
|  | return; | 
|  | } | 
|  |  | 
|  | #define MERGE_QUOTA(name, quota, dq)				\ | 
|  | do {								\ | 
|  | if (dq.name != NULL) {					\ | 
|  | quota->name[1] = dq.name[0];			\ | 
|  | quota->name[2] = dq.name[1];			\ | 
|  | }							\ | 
|  | } while(0); | 
|  |  | 
|  | static void merge_conf(struct Cveinfo *ve, vps_res *res, vps_opt *opt) | 
|  | { | 
|  | if (ve->ubc == NULL) { | 
|  | ve->ubc = x_malloc(sizeof(struct Cubc)); | 
|  | memset(ve->ubc, 0, sizeof(struct Cubc)); | 
|  | #define MERGE_UBC(name)						\ | 
|  | if (res != NULL && res->ub.name != NULL) {		\ | 
|  | ve->ubc->name[2] = res->ub.name[0];		\ | 
|  | ve->ubc->name[3] = res->ub.name[1];		\ | 
|  | } | 
|  |  | 
|  | FOR_ALL_UBC(MERGE_UBC) | 
|  |  | 
|  | #undef MERGE_UBC | 
|  | } | 
|  |  | 
|  | if (res->ub.vm_overcommit != NULL) | 
|  | ve->vm_overcommit = *res->ub.vm_overcommit; | 
|  |  | 
|  | if (ve->ip == NULL && !list_empty(&res->net.ip)) { | 
|  | ve->ip = list2str(NULL, &res->net.ip); | 
|  | } | 
|  | if (ve->quota == NULL && ( | 
|  | res->dq.diskspace != NULL || | 
|  | res->dq.diskinodes != NULL)) | 
|  | { | 
|  | ve->quota = x_malloc(sizeof(struct Cquota)); | 
|  | memset(ve->quota, 0, sizeof(struct Cquota)); | 
|  |  | 
|  | if (res->dq.diskspace) | 
|  | MERGE_QUOTA(diskspace, ve->quota, res->dq); | 
|  | if (res->dq.diskinodes) | 
|  | MERGE_QUOTA(diskinodes, ve->quota, res->dq); | 
|  |  | 
|  | } | 
|  | if (ve->cpu == NULL && | 
|  | (res->cpu.units != NULL || res->cpu.limit != NULL)) | 
|  | { | 
|  | ve->cpu = x_malloc(sizeof(struct Ccpu)); | 
|  | memset(ve->cpu, 0, sizeof(struct Ccpu)); | 
|  | if (res->cpu.limit != NULL) | 
|  | ve->cpu->limit[0] = *res->cpu.limit; | 
|  | if (res->cpu.units != NULL) | 
|  | ve->cpu->units[0] = *res->cpu.units; | 
|  | } | 
|  | if (res->misc.hostname != NULL) | 
|  | ve->hostname = strdup(res->misc.hostname); | 
|  | if (res->misc.description != NULL) | 
|  | ve->description = strdup(res->misc.description); | 
|  | if (res->tmpl.ostmpl != NULL) | 
|  | ve->ostemplate = strdup(res->tmpl.ostmpl); | 
|  | if (res->name.name != NULL) { | 
|  | int veid_nm = get_veid_by_name(res->name.name); | 
|  | if (veid_nm == ve->veid) | 
|  | ve->name = strdup(res->name.name); | 
|  | } | 
|  | if (!list_empty(&res->misc.nameserver)) | 
|  | ve->nameserver = list2str(NULL, &res->misc.nameserver); | 
|  | if (!list_empty(&res->misc.searchdomain)) | 
|  | ve->searchdomain = list2str(NULL, &res->misc.searchdomain); | 
|  |  | 
|  | if (res->fs.root != NULL) | 
|  | ve->root = strdup(res->fs.root); | 
|  | if (res->fs.private != NULL) | 
|  | ve->private = strdup(res->fs.private); | 
|  | if (res->fs.mount_opts != NULL) | 
|  | ve->mount_opts = strdup(res->fs.mount_opts); | 
|  | ve->onboot = res->misc.onboot; | 
|  | if (res->misc.bootorder != NULL) { | 
|  | ve->bootorder = x_malloc(sizeof(*ve->bootorder)); | 
|  | *ve->bootorder = *res->misc.bootorder; | 
|  | } | 
|  |  | 
|  | ve->io.ioprio = res->io.ioprio; | 
|  | ve->io.iolimit = res->io.iolimit; | 
|  | ve->io.iopslimit = res->io.iopslimit; | 
|  |  | 
|  | if (ve->cpunum == -1 && res->cpu.vcpus != NULL) | 
|  | ve->cpunum = *res->cpu.vcpus; | 
|  | ve->features_mask  = res->env.features_mask; | 
|  | ve->features_known = res->env.features_known; | 
|  | ve->disabled = opt->start_disabled; | 
|  | if (opt->origin_sample != NULL) | 
|  | ve->origin_sample = strdup(opt->origin_sample); | 
|  | } | 
|  |  | 
|  | static int read_ves_param() | 
|  | { | 
|  | int i; | 
|  | char buf[128]; | 
|  | vps_param *param; | 
|  | char *ve_root = NULL; | 
|  | char *ve_private = NULL; | 
|  | int veid; | 
|  |  | 
|  | param = init_vps_param(); | 
|  | /* Parse global config file */ | 
|  | vps_parse_config(0, GLOBAL_CFG, param, NULL); | 
|  | if (param->res.fs.root != NULL) | 
|  | ve_root = strdup(param->res.fs.root_orig); | 
|  | if (param->res.fs.private != NULL) | 
|  | ve_private = strdup(param->res.fs.private_orig); | 
|  | if (param->res.cpt.dumpdir != NULL) | 
|  | dumpdir = strdup(param->res.cpt.dumpdir); | 
|  | free_vps_param(param); | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | veid = veinfo[i].veid; | 
|  | param = init_vps_param(); | 
|  | snprintf(buf, sizeof(buf), VPSCONFDIR "/%d.conf", veid); | 
|  | vps_parse_config(veid, buf, param, NULL); | 
|  | merge_conf(&veinfo[i], ¶m->res, ¶m->opt); | 
|  | if (veinfo[i].root == NULL) | 
|  | veinfo[i].root = subst_VEID(veinfo[i].veid, ve_root); | 
|  | if (veinfo[i].private == NULL) | 
|  | veinfo[i].private = subst_VEID(veinfo[i].veid, | 
|  | ve_private); | 
|  | free_vps_param(param); | 
|  | } | 
|  | free(ve_root); | 
|  | free(ve_private); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int check_veid_restr(int veid) | 
|  | { | 
|  | if (g_ve_list == NULL) | 
|  | return 1; | 
|  | return (bsearch(&veid, g_ve_list, n_ve_list, | 
|  | sizeof(*g_ve_list), veid_search_fn) != NULL); | 
|  | } | 
|  |  | 
|  | #define UPDATE_UBC(param)			\ | 
|  | if (!strcmp(name, #param)) {		\ | 
|  | ubc.param[0] = held;		\ | 
|  | ubc.param[1] = maxheld;		\ | 
|  | ubc.param[2] = barrier;		\ | 
|  | ubc.param[3] = limit;		\ | 
|  | ubc.param[4] = failcnt;		\ | 
|  | } | 
|  |  | 
|  | static int get_ub() | 
|  | { | 
|  | char buf[256]; | 
|  | int veid, prev_veid; | 
|  | unsigned long held, maxheld, barrier, limit, failcnt; | 
|  | char name[32]; | 
|  | FILE *fp; | 
|  | char *s; | 
|  | struct Cubc ubc = {}; | 
|  |  | 
|  | if ((fp = fopen(PROC_BC_RES, "r")) == NULL) { | 
|  | if ((fp = fopen(PROCUBC, "r")) == NULL) { | 
|  | fprintf(stderr, "Unable to open %s: %s\n", | 
|  | PROCUBC, strerror(errno)); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | veid = 0; | 
|  | while (!feof(fp)) { | 
|  | if (fgets(buf, sizeof(buf), fp) == NULL) | 
|  | break; | 
|  | if ((s = strchr(buf, ':')) != NULL) { | 
|  | prev_veid = veid; | 
|  | if (sscanf(buf, "%d:", &veid) != 1) | 
|  | continue; | 
|  | if (prev_veid && check_veid_restr(prev_veid)) { | 
|  | update_ubc(prev_veid, &ubc); | 
|  | } | 
|  | memset(&ubc, 0, sizeof(struct Cubc)); | 
|  | s++; | 
|  | } else { | 
|  | s = buf; | 
|  | } | 
|  | if (sscanf(s, "%s %lu %lu %lu %lu %lu", | 
|  | name, &held, &maxheld, &barrier, &limit, &failcnt) != 6) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | FOR_ALL_UBC(UPDATE_UBC) | 
|  | } | 
|  | if (veid && check_veid_restr(veid)) { | 
|  | update_ubc(veid, &ubc); | 
|  | } | 
|  | fclose(fp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static char *invert_ip(char *ips) | 
|  | { | 
|  | char *tmp, *p, *ep, *tp; | 
|  | size_t len; | 
|  | int rc; | 
|  | unsigned int ip[4]; | 
|  | int family; | 
|  | char ip_str[INET6_ADDRSTRLEN]; | 
|  |  | 
|  | if (ips == NULL) | 
|  | return NULL; | 
|  | len = strlen(ips); | 
|  | tp = tmp = x_malloc(len + 2); | 
|  | tmp[0] = 0; | 
|  | p = ep = ips + len; | 
|  | /* Iterate in reverse order */ | 
|  | while (p-- > ips) { | 
|  | /* Skip spaces */ | 
|  | while (p > ips && isspace(*p)) {--p;} | 
|  | ep = p; | 
|  | /* find the string begin from */ | 
|  | while (p > ips && !isspace(*(p - 1))) { --p;} | 
|  | len = ep - p + 1; | 
|  | if (len >= sizeof(ip_str)) | 
|  | continue; | 
|  | strncpy(ip_str, p, len); | 
|  | ip_str[len] = 0; | 
|  | if ((family = get_netaddr(ip_str, ip)) == -1) | 
|  | continue; | 
|  | if ((inet_ntop(family, ip, ip_str, sizeof(ip_str) - 1)) == NULL) | 
|  | continue; | 
|  | rc = sprintf(tp, "%s ", ip_str); | 
|  | if (rc == -1) | 
|  | break; | 
|  | tp += rc; | 
|  | } | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | static int get_run_ve_proc(int update) | 
|  | { | 
|  | FILE *fp; | 
|  | struct Cveinfo ve; | 
|  | char buf[16384]; | 
|  | char ips[16384]; | 
|  | int res, veid, classid, nproc; | 
|  |  | 
|  | if ((fp = fopen(PROCVEINFO, "r")) == NULL) { | 
|  | fprintf(stderr, "Unable to open %s: %s\n", | 
|  | PROCVEINFO, strerror(errno)); | 
|  | return 1; | 
|  | } | 
|  | memset(&ve, 0, sizeof(struct Cveinfo)); | 
|  | while (!feof(fp)) { | 
|  | if (fgets(buf, sizeof(buf), fp) == NULL) | 
|  | break; | 
|  | res = sscanf(buf, "%d %d %d %[^\n]", | 
|  | &veid, &classid, &nproc, ips); | 
|  | if (res < 3 || !veid) | 
|  | continue; | 
|  | if (!check_veid_restr(veid)) | 
|  | continue; | 
|  | memset(&ve, 0, sizeof(struct Cveinfo)); | 
|  | if (res == 4) { | 
|  | ve.ip = invert_ip(ips); | 
|  |  | 
|  | } | 
|  | ve.veid = veid; | 
|  | ve.status = VE_RUNNING; | 
|  | if (update) | 
|  | update_ve(veid, ve.ip, ve.status); | 
|  | else | 
|  | add_elem(&ve); | 
|  | } | 
|  | if (!update) | 
|  | qsort(veinfo, n_veinfo, sizeof(struct Cveinfo), id_sort_fn); | 
|  | fclose(fp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if HAVE_VZLIST_IOCTL | 
|  | static inline int get_ve_ips(unsigned int id, char **str) | 
|  | { | 
|  | int ret = -1; | 
|  | struct vzlist_veipv4ctl veip; | 
|  | uint32_t *addr; | 
|  |  | 
|  | veip.veid = id; | 
|  | veip.num = 256; | 
|  | addr = x_malloc(veip.num * sizeof(*veip.ip)); | 
|  | for (;;) { | 
|  | veip.ip = addr; | 
|  | ret = ioctl(vzctlfd, VZCTL_GET_VEIPS, &veip); | 
|  | if (ret < 0) | 
|  | goto out; | 
|  | else if (ret <= veip.num) | 
|  | break; | 
|  | veip.num = ret; | 
|  | addr = x_realloc(addr, veip.num * sizeof(*veip.ip)); | 
|  | } | 
|  | if (ret > 0) { | 
|  | char *buf, *cp; | 
|  | int i; | 
|  |  | 
|  | buf = x_malloc(ret * (16 * sizeof(char)) + 1); | 
|  | cp = buf; | 
|  | for (i = ret - 1; i >= 0; i--) | 
|  | cp += sprintf(cp, "%d.%d.%d.%d ", NIPQUAD(addr[i])); | 
|  | *cp = '\0'; | 
|  | *str = buf; | 
|  | } else | 
|  | *str = strdup(""); | 
|  | out: | 
|  | free(addr); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int get_run_ve_ioctl(int update) | 
|  | { | 
|  | int ret = -1; | 
|  | struct vzlist_veidctl veid; | 
|  | int nves; | 
|  | void *buf = NULL; | 
|  | int i; | 
|  |  | 
|  | vzctlfd = open(VZCTLDEV, O_RDWR); | 
|  | if (vzctlfd < 0) | 
|  | goto error; | 
|  | veid.num = 256; | 
|  | buf = x_malloc(veid.num * sizeof(envid_t)); | 
|  | while (1) { | 
|  | veid.id = buf; | 
|  | ret = ioctl(vzctlfd, VZCTL_GET_VEIDS, &veid); | 
|  | if (ret < 0) | 
|  | goto out; | 
|  | if (ret <= veid.num) | 
|  | break; | 
|  | veid.num = ret + 20; | 
|  | buf = x_realloc(buf, veid.num * sizeof(envid_t)); | 
|  | } | 
|  | nves = ret; | 
|  | for (i = 0; i < nves; i++) { | 
|  | struct Cveinfo ve; | 
|  | envid_t id; | 
|  |  | 
|  | id = veid.id[i]; | 
|  | if (!id || !check_veid_restr(id)) | 
|  | continue; | 
|  | memset(&ve, '\0', sizeof(ve)); | 
|  | ve.veid = id; | 
|  | ve.status = VE_RUNNING; | 
|  | ret = get_ve_ips(id, &ve.ip); | 
|  | if (ret < 0) { | 
|  | if (errno != ESRCH) | 
|  | goto out; | 
|  | continue; | 
|  | } | 
|  | if (update) | 
|  | update_ve(id, ve.ip, ve.status); | 
|  | else | 
|  | add_elem(&ve); | 
|  | } | 
|  | if (!update) | 
|  | qsort(veinfo, n_veinfo, sizeof(struct Cveinfo), id_sort_fn); | 
|  | ret = 0; | 
|  | out: | 
|  | free(buf); | 
|  | close(vzctlfd); | 
|  | error: | 
|  | return ret; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static int get_run_quota_stat() | 
|  | { | 
|  | unsigned long usage, softlimit, hardlimit, time, exp; | 
|  | int veid = 0, prev_veid = 0; | 
|  | struct Cquota quota; | 
|  | FILE *fp; | 
|  | char buf[128]; | 
|  | char str[11]; | 
|  |  | 
|  | if ((fp = fopen(PROCQUOTA, "r")) == NULL) { | 
|  | return 1; | 
|  | } | 
|  | veid = 0; | 
|  | while (!feof(fp)) { | 
|  | if (fgets(buf, sizeof(buf), fp) == NULL) | 
|  | break; | 
|  | if (strchr(buf, ':') != NULL) { | 
|  | prev_veid = veid; | 
|  | if (sscanf(buf, "%d:", &veid) != 1) | 
|  | continue; | 
|  | if (prev_veid) | 
|  | update_quota(prev_veid, "a); | 
|  | memset("a, 0, sizeof(quota)); | 
|  | continue; | 
|  |  | 
|  | } | 
|  | if (sscanf(buf, "%10s %lu %lu %lu %lu %lu", str, &usage, | 
|  | &softlimit, &hardlimit, &time, &exp) == 6) | 
|  | { | 
|  | if (!strcmp(str, "1k-blocks")) { | 
|  | quota.diskspace[0] = usage; | 
|  | quota.diskspace[1] = softlimit; | 
|  | quota.diskspace[2] = hardlimit; | 
|  | } else if (!strcmp(str, "inodes")) { | 
|  | quota.diskinodes[0] = usage; | 
|  | quota.diskinodes[1] = softlimit; | 
|  | quota.diskinodes[2] = hardlimit; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (veid) | 
|  | update_quota(veid, "a); | 
|  | fclose(fp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_ve_ploop_info(struct Cveinfo *ve) | 
|  | { | 
|  | #ifdef HAVE_PLOOP | 
|  | char descr[PATH_MAX]; | 
|  | struct ploop_info i = {}; | 
|  |  | 
|  | ploop.set_verbose_level(PLOOP_LOG_NOSTDOUT); | 
|  | GET_DISK_DESCRIPTOR(descr, ve->private); | 
|  | if (ploop.get_info_by_descr(descr, &i)) | 
|  | return -1; | 
|  |  | 
|  | if (ve->quota == NULL) { | 
|  | ve->quota = x_malloc(sizeof(struct Cquota)); | 
|  | memset(ve->quota, 0, sizeof(struct Cquota)); | 
|  | } | 
|  |  | 
|  | // space avail | 
|  | ve->quota->diskspace[1] = ve->quota->diskspace[2] = | 
|  | (i.fs_blocks * i.fs_bsize) >> 10; | 
|  | // space used | 
|  | ve->quota->diskspace[0] = | 
|  | ((i.fs_blocks - i.fs_bfree) * i.fs_bsize) >> 10; | 
|  |  | 
|  | // inodes avail | 
|  | ve->quota->diskinodes[1] = ve->quota->diskinodes[2] = | 
|  | i.fs_inodes; | 
|  | // inodes used | 
|  | ve->quota->diskinodes[0] = i.fs_inodes - i.fs_ifree; | 
|  | #else | 
|  | static int shown = 0; | 
|  |  | 
|  | if (!shown) { | 
|  | fprintf(stderr, "Warning: ploop support is not compiled in\n"); | 
|  | shown = 1; | 
|  | } | 
|  | #endif /* HAVE_PLOOP */ | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_ves_ploop_info() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (veinfo[i].layout == VE_LAYOUT_PLOOP && !veinfo[i].hide | 
|  | && is_ploop_supported()) | 
|  | get_ve_ploop_info(&veinfo[i]); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static long get_clk_tck() | 
|  | { | 
|  | if (__clk_tck != -1) | 
|  | return __clk_tck; | 
|  | __clk_tck = sysconf(_SC_CLK_TCK); | 
|  | return __clk_tck; | 
|  | } | 
|  |  | 
|  | static int get_ve_cpustat(struct Cveinfo *ve) | 
|  | { | 
|  | struct vz_cpu_stat stat; | 
|  | struct vzctl_cpustatctl statctl; | 
|  | struct Ccpustat st; | 
|  |  | 
|  | statctl.veid = ve->veid; | 
|  | statctl.cpustat = &stat; | 
|  | if (ioctl(vzctlfd, VZCTL_GET_CPU_STAT, &statctl) != 0) | 
|  | return 1; | 
|  | st.la[0] = stat.avenrun[0].val_int + (stat.avenrun[0].val_frac * 0.01); | 
|  | st.la[1] = stat.avenrun[1].val_int + (stat.avenrun[1].val_frac * 0.01); | 
|  | st.la[2] = stat.avenrun[2].val_int + (stat.avenrun[2].val_frac * 0.01); | 
|  |  | 
|  | st.uptime = (float) stat.uptime_jif / get_clk_tck(); | 
|  |  | 
|  | ve->cpustat = x_malloc(sizeof(st)); | 
|  | memcpy(ve->cpustat, &st, sizeof(st)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_ves_cpustat() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if ((vzctlfd = open(VZCTLDEV, O_RDWR)) < 0) | 
|  | return 1; | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (veinfo[i].hide) | 
|  | continue; | 
|  | get_ve_cpustat(&veinfo[i]); | 
|  | } | 
|  | close(vzctlfd); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_mounted_status(int detailed) | 
|  | { | 
|  | int i; | 
|  | char buf[512]; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if (veinfo[i].status == VE_RUNNING) | 
|  | continue; | 
|  | if (veinfo[i].private == NULL || | 
|  | stat_file(veinfo[i].private) != 1) | 
|  | { | 
|  | veinfo[i].hide = 1; | 
|  | continue; | 
|  | } | 
|  | if (!detailed) | 
|  | continue; | 
|  | get_dump_file(veinfo[i].veid, dumpdir, buf, sizeof(buf)); | 
|  | if (stat_file(buf) == 1) | 
|  | veinfo[i].status = VE_SUSPENDED; | 
|  | if (veinfo[i].root == NULL) | 
|  | continue; | 
|  | if (vps_is_mounted(veinfo[i].root, veinfo[i].private) == 1) | 
|  | veinfo[i].status = VE_MOUNTED; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_ves_layout() | 
|  | { | 
|  | int i, ploop; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | ploop = ve_private_is_ploop(veinfo[i].private); | 
|  | veinfo[i].layout = ploop ? VE_LAYOUT_PLOOP : VE_LAYOUT_SIMFS; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_ve_cpunum(struct Cveinfo *ve) { | 
|  | char path[] = "/proc/vz/fairsched/2147483647/cpu.nr_cpus"; | 
|  | int veid = ve->veid; | 
|  | FILE *fp; | 
|  | int ret = -1; | 
|  |  | 
|  | snprintf(path, sizeof(path), | 
|  | "/proc/vz/fairsched/%d/cpu.nr_cpus", veid); | 
|  | fp = fopen(path, "r"); | 
|  | if (fp == NULL) { | 
|  | fprintf(stderr, "Unable to open %s: %s\n", | 
|  | path, strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | if (fscanf(fp, "%d", &ve->cpunum) != 1) | 
|  | goto out; | 
|  |  | 
|  | ret = 0; | 
|  | out: | 
|  | fclose(fp); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void get_ves_cpunum() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if (access("/proc/vz/fairsched/", F_OK)) | 
|  | /* pre-RHEL6 kernel */ | 
|  | return; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if ((veinfo[i].hide) || (veinfo[i].status != VE_RUNNING)) | 
|  | continue; | 
|  | get_ve_cpunum(&veinfo[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int get_ves_cpu() | 
|  | { | 
|  | unsigned long tmp; | 
|  | int veid, id, weight, rate; | 
|  | FILE *fp; | 
|  | char buf[128]; | 
|  |  | 
|  | if ((fp = fopen(PROCFSHED, "r")) == NULL) { | 
|  | fprintf(stderr, "Unable to open %s: %s\n", | 
|  | PROCFSHED, strerror(errno)); | 
|  | return 1; | 
|  | } | 
|  | veid = 0; | 
|  | while (!feof(fp)) { | 
|  | if (fgets(buf, sizeof(buf), fp) == NULL) | 
|  | break; | 
|  | if (sscanf(buf, "%d %d %lu %d %d", | 
|  | &veid, &id, &tmp, &weight, &rate) != 5) | 
|  | { | 
|  | continue; | 
|  | } | 
|  | if (id && !veid) { | 
|  | rate = rint((double)rate * 100 / 1024); | 
|  | weight = rint((double)MAXCPUUNITS / weight); | 
|  | update_cpu(id, rate, weight); | 
|  | } | 
|  | } | 
|  | fclose(fp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int update_ves_io(void) | 
|  | { | 
|  | int limit, i; | 
|  |  | 
|  | if ((vzctlfd = open(VZCTLDEV, O_RDWR)) < 0) | 
|  | return 1; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | if ((veinfo[i].hide) || (veinfo[i].status != VE_RUNNING)) | 
|  | continue; | 
|  |  | 
|  | if (vzctl_get_iolimit(vzctlfd, veinfo[i].veid, &limit) == 0) | 
|  | veinfo[i].io.iolimit = limit; | 
|  |  | 
|  | if (vzctl_get_iopslimit(vzctlfd, veinfo[i].veid, &limit) == 0) | 
|  | veinfo[i].io.iopslimit = limit; | 
|  | } | 
|  | close(vzctlfd); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int get_ve_list() | 
|  | { | 
|  | DIR *dp; | 
|  | struct dirent *ep; | 
|  | int veid, res; | 
|  | struct Cveinfo ve; | 
|  | char str[6]; | 
|  |  | 
|  | dp = opendir(VPSCONFDIR); | 
|  | if (dp == NULL) { | 
|  | return -1; | 
|  | } | 
|  | memset(&ve, 0, sizeof(struct Cveinfo)); | 
|  | ve.status = VE_STOPPED; | 
|  | while ((ep = readdir (dp))) { | 
|  | res = sscanf(ep->d_name, "%d.%5s", &veid, str); | 
|  | if (!(res == 2 && !strcmp(str, "conf"))) | 
|  | continue; | 
|  | if (veid < 0 || veid > VEID_MAX) { | 
|  | fprintf(stderr, "Warning: invalid CTID in config file " | 
|  | "name: %s, skipping\n", ep->d_name); | 
|  | continue; | 
|  | } | 
|  | if (!check_veid_restr(veid)) | 
|  | continue; | 
|  | ve.veid = veid; | 
|  | add_elem(&ve); | 
|  | } | 
|  | closedir(dp); | 
|  | if (veinfo != NULL) | 
|  | qsort(veinfo, n_veinfo, sizeof(struct Cveinfo), id_sort_fn); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int search_field(char *name) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | if (name == NULL) | 
|  | return -1; | 
|  | for (i = 0; i < ARRAY_SIZE(field_names); i++) { | 
|  | if (!strcmp(name, field_names[i].name)) | 
|  | return i; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static int build_field_order(char *fields) | 
|  | { | 
|  | struct Cfield_order *tmp, *prev = NULL; | 
|  | char *sp, *ep, *p; | 
|  | char name[32]; | 
|  | int order; | 
|  | size_t nm_len; | 
|  |  | 
|  | sp = fields; | 
|  | if (fields == NULL) { | 
|  | if (fmt_json) | 
|  | return 0; | 
|  | sp = default_field_order; | 
|  | } | 
|  | ep = sp + strlen(sp); | 
|  | do { | 
|  | if ((p = strchr(sp, ',')) == NULL) | 
|  | p = ep; | 
|  | nm_len = p - sp + 1; | 
|  | if (nm_len > sizeof(name) - 1) { | 
|  | fprintf(stderr, "Invalid field: %s\n", sp); | 
|  | return 1; | 
|  | } | 
|  | snprintf(name, nm_len, "%s", sp); | 
|  | sp = p + 1; | 
|  | if ((order = search_field(name)) < 0) { | 
|  | fprintf(stderr, "Unknown field: %s\n", name); | 
|  | return 1; | 
|  | } | 
|  | if (fmt_json && field_names[order].index) { | 
|  | fprintf(stderr, "Field `%s' is not available " | 
|  | "in JSON output\n", name); | 
|  | return 1; | 
|  | } | 
|  | tmp = x_malloc(sizeof(struct Cfield_order)); | 
|  | tmp->order = order; | 
|  | tmp->next = NULL; | 
|  | if (prev == NULL) | 
|  | g_field_order = tmp; | 
|  | else | 
|  | prev->next = tmp; | 
|  | prev = tmp; | 
|  | } while (sp < ep); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int check_param(int res_type) | 
|  | { | 
|  | struct Cfield_order *p; | 
|  |  | 
|  | if (fmt_json && !g_field_order) | 
|  | return 1; | 
|  |  | 
|  | for (p = g_field_order; p != NULL; p = p->next) { | 
|  | if (field_names[p->order].res_type == res_type) | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int collect() | 
|  | { | 
|  | int update = 0; | 
|  | int ret; | 
|  |  | 
|  | if (all_ve || g_ve_list != NULL || only_stopped_ve) { | 
|  | get_ve_list(); | 
|  | update = 1; | 
|  | } | 
|  | get_run_ve(update); | 
|  | if (!only_stopped_ve && (ret = get_ub())) | 
|  | return ret; | 
|  | /* No CT found, exit with error */ | 
|  | if (!n_veinfo) { | 
|  | fprintf(stderr, "Container(s) not found\n"); | 
|  | return 1; | 
|  | } | 
|  | if (check_param(RES_CPUSTAT)) | 
|  | get_ves_cpustat(); | 
|  | if (check_param(RES_CPU)) | 
|  | if (!only_stopped_ve && (ret = get_ves_cpu())) | 
|  | return ret; | 
|  | if (check_param(RES_CPUNUM) && !only_stopped_ve) | 
|  | get_ves_cpunum(); | 
|  | read_ves_param(); | 
|  | if (check_param(RES_IO)) | 
|  | update_ves_io(); | 
|  | get_mounted_status(check_param(RES_STATUS)); | 
|  | get_ves_layout(); | 
|  | if (check_param(RES_QUOTA)) { | 
|  | get_run_quota_stat(); | 
|  | get_ves_ploop_info(); | 
|  | } | 
|  | if (host_pattern != NULL) | 
|  | filter_by_hostname(); | 
|  | if (name_pattern != NULL) | 
|  | filter_by_name(); | 
|  | if (desc_pattern != NULL) | 
|  | filter_by_description(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void print_names() | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(field_names); i++) | 
|  | printf("%-15s %-15s\n", field_names[i].name, | 
|  | field_names[i].hdr); | 
|  | return; | 
|  | } | 
|  |  | 
|  | static void free_veinfo() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < n_veinfo; i++) { | 
|  | free(veinfo[i].ip); | 
|  | free(veinfo[i].nameserver); | 
|  | free(veinfo[i].searchdomain); | 
|  | free(veinfo[i].hostname); | 
|  | free(veinfo[i].name); | 
|  | free(veinfo[i].description); | 
|  | free(veinfo[i].ostemplate); | 
|  | free(veinfo[i].ubc); | 
|  | free(veinfo[i].quota); | 
|  | free(veinfo[i].cpustat); | 
|  | free(veinfo[i].cpu); | 
|  | free(veinfo[i].root); | 
|  | free(veinfo[i].private); | 
|  | free(veinfo[i].mount_opts); | 
|  | free(veinfo[i].origin_sample); | 
|  | free(veinfo[i].bootorder); | 
|  | } | 
|  | } | 
|  |  | 
|  | static struct option list_options[] = | 
|  | { | 
|  | {"no-header",	no_argument, NULL, 'H'}, | 
|  | {"no-trim",	no_argument, NULL, 't'}, | 
|  | {"stopped",	no_argument, NULL, 'S'}, | 
|  | {"all",		no_argument, NULL, 'a'}, | 
|  | {"name",	no_argument, NULL, 'n'}, | 
|  | {"json",	no_argument, NULL, 'j'}, | 
|  | {"name_filter", required_argument, NULL, 'N'}, | 
|  | {"hostname",	required_argument, NULL, 'h'}, | 
|  | {"description", required_argument, NULL, 'd'}, | 
|  | {"output",	required_argument, NULL, 'o'}, | 
|  | {"sort",	required_argument, NULL, 's'}, | 
|  | {"list",	no_argument, NULL, 'L'}, | 
|  | {"help",	no_argument, NULL, 'e'}, | 
|  | { NULL, 0, NULL, 0 } | 
|  | }; | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | int ret; | 
|  | char *f_order = NULL; | 
|  | char *ep, *p; | 
|  | int veid, c; | 
|  |  | 
|  | while (1) { | 
|  | int option_index = -1; | 
|  | c = getopt_long(argc, argv, "HtSanjN:h:d:o:s:Le1", | 
|  | list_options, &option_index); | 
|  | if (c == -1) | 
|  | break; | 
|  |  | 
|  | switch(c) { | 
|  | case 'S'	: | 
|  | only_stopped_ve = 1; | 
|  | break; | 
|  | case 't'	: | 
|  | trim = 0; | 
|  | break; | 
|  | case 'H'	: | 
|  | show_hdr = 0; | 
|  | break; | 
|  | case 'L'	: | 
|  | print_names(); | 
|  | return 0; | 
|  | case 'a'	: | 
|  | all_ve = 1; | 
|  | break; | 
|  | case 'h'	: | 
|  | host_pattern = strdup(optarg); | 
|  | break; | 
|  | case 'd'	: | 
|  | desc_pattern = strdup(optarg); | 
|  | break; | 
|  | case 'o'	: | 
|  | f_order = strdup(optarg); | 
|  | break; | 
|  | case 's'	: | 
|  | p = optarg; | 
|  | if (p[0] == '-') { | 
|  | p++; | 
|  | sort_rev = 1; | 
|  | } | 
|  | if ((g_sort_field = search_field(p)) < 0) { | 
|  | fprintf(stderr, "Invalid sort field name: " | 
|  | "%s\n", optarg); | 
|  | return 1; | 
|  | } | 
|  | break; | 
|  | case '1'	: | 
|  | f_order = strdup("veid"); | 
|  | show_hdr = 0; | 
|  | break; | 
|  | case 'n'	: | 
|  | f_order = strdup(default_nm_field_order); | 
|  | break; | 
|  | case 'N'	: | 
|  | name_pattern = strdup(optarg); | 
|  | break; | 
|  | case 'j'	: | 
|  | fmt_json = 1; | 
|  | p_buf = e_buf = NULL; | 
|  | break; | 
|  | default		: | 
|  | /* "Unknown option" error msg is printed by getopt */ | 
|  | usage(); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | if (optind < argc) { | 
|  | while (optind < argc) { | 
|  | veid = strtol(argv[optind], &ep, 10); | 
|  | if (*ep != 0 || !veid) { | 
|  | veid = get_veid_by_name(argv[optind]); | 
|  | } | 
|  | if (veid < 0 || veid > VEID_MAX) { | 
|  | fprintf(stderr, "CT ID %s is invalid.\n", | 
|  | argv[optind]); | 
|  | return 1; | 
|  | } | 
|  | optind++; | 
|  | g_ve_list = x_realloc(g_ve_list, | 
|  | sizeof(*g_ve_list) * ++n_ve_list); | 
|  | g_ve_list[n_ve_list - 1] = veid; | 
|  | } | 
|  | qsort(g_ve_list, n_ve_list, sizeof(*g_ve_list), id_sort_fn); | 
|  | } | 
|  | init_log(NULL, 0, 0, 0, 0, NULL); | 
|  | if (build_field_order(f_order)) | 
|  | return 1; | 
|  | if (getuid()) { | 
|  | fprintf(stderr, "This program can only be run under root.\n"); | 
|  | return 1; | 
|  | } | 
|  | if ((ret = collect())) { | 
|  | /* If no specific CTIDs are specified in arguments, | 
|  | * 'no containers found' is not an error (bug #2149) | 
|  | */ | 
|  | if (g_ve_list == NULL) | 
|  | return 0; | 
|  | else | 
|  | return ret; | 
|  | } | 
|  | print_ve(); | 
|  | free_veinfo(); | 
|  | free(host_pattern); | 
|  | free(name_pattern); | 
|  | free(desc_pattern); | 
|  | free(f_order); | 
|  |  | 
|  | return 0; | 
|  | } |