|  | /* | 
|  | *  Copyright (C) 2000-2009, 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 | 
|  | */ | 
|  | #ifndef _GNU_SOURCE | 
|  | #define _GNU_SOURCE | 
|  | #endif | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <unistd.h> | 
|  | #include <string.h> | 
|  | #include <errno.h> | 
|  | #include <ctype.h> | 
|  | #include <sys/mman.h> | 
|  | #include <fcntl.h> | 
|  | #include <arpa/inet.h> | 
|  | #include <stdarg.h> | 
|  | #include <limits.h> | 
|  | #include <dirent.h> | 
|  |  | 
|  | #include "util.h" | 
|  | #include "logger.h" | 
|  | #include "fs.h" | 
|  |  | 
|  | #ifndef NR_OPEN | 
|  | #define NR_OPEN 1024 | 
|  | #endif | 
|  |  | 
|  | static const char *unescapestr(char *src) | 
|  | { | 
|  | char *p1, *p2; | 
|  | int fl; | 
|  |  | 
|  | if (src == NULL) | 
|  | return NULL; | 
|  | p2 = src; | 
|  | p1 = p2; | 
|  | fl = 0; | 
|  | while (*p2) { | 
|  | if (*p2 == '\\' && !fl)	{ | 
|  | fl = 1; | 
|  | p2++; | 
|  | } else { | 
|  | *p1 = *p2; | 
|  | p1++; p2++; | 
|  | fl = 0; | 
|  | } | 
|  | } | 
|  | *p1 = 0; | 
|  |  | 
|  | return src; | 
|  | } | 
|  |  | 
|  | char *parse_line(char *str, char *ltoken, int lsz, char **err) | 
|  | { | 
|  | char *sp = str; | 
|  | char *ep, *p, *ret; | 
|  | int len; | 
|  |  | 
|  | *err = NULL; | 
|  | unescapestr(str); | 
|  | while (*sp && isspace(*sp)) sp++; | 
|  | if (!*sp || *sp == '#') | 
|  | return NULL; | 
|  | ep = sp + strlen(sp) - 1; | 
|  | while (isspace(*ep) && ep >= sp) *ep-- = '\0'; | 
|  | if (!(p = strchr(sp, '='))) { | 
|  | *err = "'=' not found"; | 
|  | return NULL; | 
|  | } | 
|  | len = p - sp; | 
|  | if (len >= lsz) { | 
|  | *err = "too long value"; | 
|  | return NULL; | 
|  | } | 
|  | strncpy(ltoken, sp, len); | 
|  | ltoken[len] = 0; | 
|  | if (*(++p) != '"') | 
|  | return p; | 
|  | /* Quoted argument requires some additional processing */ | 
|  | ret = ++p; /* skip opening quote */ | 
|  | /* Find the matching closing quote */ | 
|  | if (!(p = strrchr(p, '"'))) { | 
|  | *err="unmatched quotes"; | 
|  | return NULL; | 
|  | } | 
|  | *p = '\0'; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | 1 - exist | 
|  | 0 - does't exist | 
|  | -1 - error | 
|  | */ | 
|  | int stat_file(const char *file) | 
|  | { | 
|  | struct stat st; | 
|  |  | 
|  | if (stat(file, &st)) { | 
|  | if (errno != ENOENT) | 
|  | return -1; | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int make_dir_mode(const char *path, int full, int mode) | 
|  | { | 
|  | char buf[4096]; | 
|  | const char *ps, *p; | 
|  | int len; | 
|  |  | 
|  | if (path == NULL) | 
|  | return 0; | 
|  |  | 
|  | ps = path + 1; | 
|  | while ((p = strchr(ps, '/'))) { | 
|  | len = p - path + 1; | 
|  | snprintf(buf, len, "%s", path); | 
|  | ps = p + 1; | 
|  | if (!stat_file(buf)) { | 
|  | if (mkdir(buf, mode)) { | 
|  | logger(-1, errno, "Can't create directory %s", | 
|  | buf); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (!full) | 
|  | return 0; | 
|  | if (!stat_file(path)) { | 
|  | if (mkdir(path, mode)) { | 
|  | logger(-1, errno, "Can't create directory %s", path); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int make_dir(const char *path, int full) | 
|  | { | 
|  | return make_dir_mode(path, full, 0755); | 
|  | } | 
|  |  | 
|  | char *get_fs_root(const char *dir) | 
|  | { | 
|  | struct stat st; | 
|  | dev_t id; | 
|  | size_t len; | 
|  | const char *p, *prev; | 
|  | char tmp[PATH_MAX]; | 
|  |  | 
|  | if (stat(dir, &st) < 0) | 
|  | return NULL; | 
|  | id = st.st_dev; | 
|  | len = strlen(dir); | 
|  | if (len > sizeof(tmp) - 1) { | 
|  | errno = ERANGE; | 
|  | return NULL; | 
|  | } | 
|  | p = dir + len; | 
|  | prev = p; | 
|  | while (p > dir) { | 
|  | while (p > dir && *p == '/') p--; | 
|  | while (p > dir && *p != '/') p--; | 
|  | if (p <= dir) | 
|  | break; | 
|  | len = p - dir + 1; | 
|  | strncpy(tmp, dir, len); | 
|  | tmp[len] = 0; | 
|  | if (stat(tmp, &st) < 0) | 
|  | return NULL; | 
|  | if (id != st.st_dev) | 
|  | break; | 
|  | prev = p; | 
|  | } | 
|  | len = prev - dir; | 
|  | if (len) { | 
|  | strncpy(tmp, dir, len); | 
|  | tmp[len] = 0; | 
|  | return strdup(tmp); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | int parse_int(const char *str, int *val) | 
|  | { | 
|  | char *tail; | 
|  | long res; | 
|  |  | 
|  | res = strtol(str, &tail, 10); | 
|  | if (*tail != '\0' || res < INT_MIN || res > INT_MAX) | 
|  | return 1; | 
|  | *val = (int)res; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int parse_ul(const char *str, unsigned long *val) | 
|  | { | 
|  | char *tail; | 
|  | unsigned long res; | 
|  |  | 
|  | if (!strcmp(str, "unlimited")) { | 
|  | *val = LONG_MAX; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | res = strtoul(str, &tail, 10); | 
|  | if (*tail != '\0' || res > LONG_MAX) | 
|  | return ERR_INVAL; | 
|  | *val = res; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int check_var(const void *val, const char *message) | 
|  | { | 
|  | if (val != NULL) | 
|  | return 0; | 
|  | logger(-1, 0, "%s", message); | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int cp_file(char *dst, char *src) | 
|  | { | 
|  | int fd_src, fd_dst, ret = 0; | 
|  | struct stat st; | 
|  | char buf[4096]; | 
|  |  | 
|  | if (stat(src, &st) < 0) { | 
|  | logger(-1, errno, "Unable to stat %s", src); | 
|  | return -1; | 
|  | } | 
|  | if ((fd_src = open(src, O_RDONLY)) < 0) { | 
|  | logger(-1, errno, "Unable to open %s", src); | 
|  | return -1; | 
|  | } | 
|  | if ((fd_dst = open(dst, O_CREAT|O_TRUNC|O_RDWR, st.st_mode)) < 0) { | 
|  | logger(-1, errno, "Unable to open %s", dst); | 
|  | close(fd_src); | 
|  | return -1; | 
|  | } | 
|  | while(1) { | 
|  | ret = read(fd_src, buf, sizeof(buf)); | 
|  | if (!ret) | 
|  | break; | 
|  | else if (ret < 0) { | 
|  | logger(-1, errno, "Unable to read from %s", src); | 
|  | ret = -1; | 
|  | break; | 
|  | } | 
|  | if (write(fd_dst, buf, ret) < 0) { | 
|  | logger(-1, errno, "Unable to write to %s", dst); | 
|  | ret = -1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | close(fd_src); | 
|  | close(fd_dst); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void get_vps_conf_path(envid_t veid, char *buf, int len) | 
|  | { | 
|  | snprintf(buf, len, VPS_CONF_DIR "%d.conf", veid); | 
|  | } | 
|  |  | 
|  | char *arg2str(char **arg) | 
|  | { | 
|  | char **p; | 
|  | char *str, *sp; | 
|  | int len = 0; | 
|  |  | 
|  | if (arg == NULL) | 
|  | return NULL; | 
|  | p = arg; | 
|  | while (*p) | 
|  | len += strlen(*p++) + 1; | 
|  | if ((str = (char *)malloc(len + 1)) == NULL) | 
|  | return NULL; | 
|  | p = arg; | 
|  | sp = str; | 
|  | while (*p) | 
|  | sp += sprintf(sp, "%s ", *p++); | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | void free_arg(char **arg) | 
|  | { | 
|  | while (*arg) free(*arg++); | 
|  | } | 
|  |  | 
|  | inline unsigned long max_ul(unsigned long val1, unsigned long val2) | 
|  | { | 
|  | return (val1 > val2) ? val1 : val2; | 
|  | } | 
|  |  | 
|  | inline unsigned long min_ul(unsigned long val1, unsigned long val2) | 
|  | { | 
|  | return (val1 < val2) ? val1 : val2; | 
|  | } | 
|  |  | 
|  | int yesno2id(const char *str) | 
|  | { | 
|  | if (!strcmp(str, "yes")) | 
|  | return YES; | 
|  | else if (!strcmp(str, "no")) | 
|  | return NO; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int get_addr_family(const char *addr) | 
|  | { | 
|  | if (strchr(addr, ':')) | 
|  | return AF_INET6; | 
|  | else | 
|  | return AF_INET; | 
|  | } | 
|  |  | 
|  | int get_netaddr(const char *ip_str, void *ip) | 
|  | { | 
|  | int family; | 
|  |  | 
|  | family = get_addr_family(ip_str); | 
|  |  | 
|  | if (inet_pton(family, ip_str, ip) <= 0) | 
|  | return -1; | 
|  | return family; | 
|  | } | 
|  |  | 
|  | static inline int max_netmask(int family) | 
|  | { | 
|  | if (family == AF_INET) | 
|  | return 32; | 
|  | else if (family == AF_INET6) | 
|  | return 128; | 
|  | else | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Check and "canonicalize" an IP address with optional netmask | 
|  | * (in CIDR notation). Basically */ | 
|  | char *canon_ip(const char *str) | 
|  | { | 
|  | const char *ipstr, *maskstr; | 
|  | int mask, family; | 
|  | unsigned int ip[4]; | 
|  | static char dst[INET6_ADDRSTRLEN + sizeof("/128")]; | 
|  |  | 
|  | maskstr = strchr(str, '/'); | 
|  | if (maskstr) { | 
|  | ipstr = strndupa(str, maskstr - str); | 
|  | maskstr++; | 
|  | } | 
|  | else { | 
|  | ipstr = str; | 
|  | } | 
|  | family = get_netaddr(ipstr, ip); | 
|  | if (family < 0) | 
|  | return NULL; | 
|  | if ((inet_ntop(family, ip, dst, sizeof(dst))) == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (maskstr == NULL) | 
|  | goto out; | 
|  |  | 
|  | /* Parse netmask */ | 
|  | if (parse_int(maskstr, &mask) != 0) | 
|  | return NULL; | 
|  | if (mask > max_netmask(family) || mask < 0) | 
|  | return NULL; | 
|  | sprintf(dst + strlen(dst), "/%d", mask); | 
|  |  | 
|  | out: | 
|  | return dst; | 
|  | } | 
|  |  | 
|  | char *subst_VEID(envid_t veid, char *src) | 
|  | { | 
|  | char *srcp; | 
|  | char str[STR_SIZE]; | 
|  | char *sp, *se; | 
|  | int r; | 
|  | unsigned int len, veidlen; | 
|  |  | 
|  | if (src == NULL) | 
|  | return NULL; | 
|  | /* Skip end '/' */ | 
|  | se = src + strlen(src) - 1; | 
|  | while (se != str && *se == '/') { | 
|  | *se = 0; | 
|  | se--; | 
|  | } | 
|  | if ((srcp = strstr(src, "$VEID"))) | 
|  | veidlen = sizeof("$VEID") - 1; | 
|  | else if ((srcp = strstr(src, "${VEID}"))) | 
|  | veidlen = sizeof("${VEID}") - 1; | 
|  | else | 
|  | return strdup(src); | 
|  |  | 
|  | sp = str; | 
|  | se = str + sizeof(str); | 
|  | len = srcp - src; /* Length of src before $VEID */ | 
|  | if (len > sizeof(str)) | 
|  | return NULL; | 
|  | memcpy(str, src, len); | 
|  | sp += len; | 
|  | r = snprintf(sp, se - sp, "%d", veid); | 
|  | sp += r; | 
|  | if ((r < 0) || (sp >= se)) | 
|  | return NULL; | 
|  | if (*srcp) { | 
|  | r = snprintf(sp, se - sp, "%s", srcp + veidlen); | 
|  | sp += r; | 
|  | if ((r < 0) || (sp >= se)) | 
|  | return NULL; | 
|  | } | 
|  | return strdup(str); | 
|  | } | 
|  |  | 
|  | int get_pagesize() | 
|  | { | 
|  | long pagesize; | 
|  |  | 
|  | if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) { | 
|  | logger(-1, errno, "Unable to get page size"); | 
|  | return -1; | 
|  | } | 
|  | return pagesize; | 
|  | } | 
|  |  | 
|  | int get_mem(unsigned long long *mem) | 
|  | { | 
|  | long pages, pagesize; | 
|  | if ((pages = sysconf(_SC_PHYS_PAGES)) == -1) { | 
|  | logger(-1, errno, "Unable to get total phys pages"); | 
|  | return -1; | 
|  | } | 
|  | if ((pagesize = get_pagesize()) < 0) | 
|  | return -1; | 
|  | *mem = (unsigned long long) pages * pagesize; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int get_thrmax(int *thrmax) | 
|  | { | 
|  | FILE *fd; | 
|  | char str[128]; | 
|  |  | 
|  | if (thrmax == NULL) | 
|  | return 1; | 
|  | if ((fd = fopen(PROCTHR, "r")) == NULL) { | 
|  | logger(-1, errno, "Unable to open " PROCTHR); | 
|  | return 1; | 
|  | } | 
|  | if (fgets(str, sizeof(str), fd) == NULL) { | 
|  | fclose(fd); | 
|  | return 1; | 
|  | } | 
|  | fclose(fd); | 
|  | if (sscanf(str, "%du", thrmax) != 1) | 
|  | return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int get_swap(unsigned long long *swap) | 
|  | { | 
|  | FILE *fd; | 
|  | char str[128]; | 
|  |  | 
|  | if ((fd = fopen(PROCMEM, "r")) == NULL)	{ | 
|  | logger(-1, errno, "Cannot open " PROCMEM); | 
|  | return -1; | 
|  | } | 
|  | while (fgets(str, sizeof(str), fd)) { | 
|  | if (sscanf(str, "SwapTotal: %llu", swap) == 1) { | 
|  | *swap *= 1024; | 
|  | fclose(fd); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | logger(-1, errno, "Swap: is not found in " PROCMEM ); | 
|  | fclose(fd); | 
|  |  | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int get_num_cpu() | 
|  | { | 
|  | FILE *fd; | 
|  | char str[128]; | 
|  | int ncpu = 0; | 
|  |  | 
|  | if ((fd = fopen("/proc/cpuinfo", "r")) == NULL)	{ | 
|  | logger(-1, errno, "Cannot open /proc/cpuinfo"); | 
|  | return 1; | 
|  | } | 
|  | while (fgets(str, sizeof(str), fd)) { | 
|  | if (!strncmp(str, "processor", 9)) | 
|  | ncpu++; | 
|  | } | 
|  | fclose(fd); | 
|  | return !ncpu ? 1 : ncpu; | 
|  | } | 
|  |  | 
|  | int get_lowmem(unsigned long long *mem) | 
|  | { | 
|  | FILE *fd; | 
|  | char str[128]; | 
|  |  | 
|  | if ((fd = fopen(PROCMEM, "r")) == NULL)	{ | 
|  | logger(-1, errno, "Cannot open " PROCMEM); | 
|  | return -1; | 
|  | } | 
|  | *mem = 0; | 
|  | while (fgets(str, sizeof(str), fd)) { | 
|  | if (sscanf(str, "LowTotal: %llu", mem) == 1) | 
|  | break; | 
|  | /* Use MemTotal in case LowTotal not found */ | 
|  | sscanf(str, "MemTotal: %llu", mem); | 
|  | } | 
|  | fclose(fd); | 
|  | if (*mem == 0) { | 
|  | fprintf(stderr, "Neither LowTotal nor MemTotal found in the " | 
|  | PROCMEM "\n"); | 
|  | return -1; | 
|  | } | 
|  | *mem *= 1024; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int get_dump_file(unsigned veid, const char *dumpdir, char *buf, int size) | 
|  | { | 
|  | return snprintf(buf, size, "%s/" DEF_DUMPFILE, | 
|  | dumpdir != NULL ? dumpdir : DEF_DUMPDIR, veid); | 
|  | } | 
|  |  | 
|  | int set_not_blk(int fd) | 
|  | { | 
|  | int oldfl, ret; | 
|  |  | 
|  | if ((oldfl = fcntl(fd, F_GETFL)) == -1) | 
|  | return -1; | 
|  | oldfl |= O_NONBLOCK; | 
|  | ret = fcntl(fd, F_SETFL, oldfl); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /** Close all fd. | 
|  | * @param close_std	flag for closing the [0-2] fds | 
|  | * @param ...		list of fds are skiped, (-1 is the end mark) | 
|  | */ | 
|  | void close_fds(int close_std, ...) | 
|  | { | 
|  | int fd, max; | 
|  | unsigned int i; | 
|  | va_list ap; | 
|  | int skip_fds[255]; | 
|  |  | 
|  | max = sysconf(_SC_OPEN_MAX); | 
|  | if (max < NR_OPEN) | 
|  | max = NR_OPEN; | 
|  | if (close_std) { | 
|  | fd = open("/dev/null", O_RDWR); | 
|  | if (fd != -1) { | 
|  | dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); | 
|  | } else { | 
|  | close(0); close(1); close(2); | 
|  | } | 
|  | } | 
|  | /* build aray of skiped fds */ | 
|  | va_start(ap, close_std); | 
|  | skip_fds[0] = -1; | 
|  | for (i = 0; i < ARRAY_SIZE(skip_fds); i++) { | 
|  | fd = va_arg(ap, int); | 
|  | skip_fds[i] = fd; | 
|  | if (fd == -1) | 
|  | break; | 
|  | } | 
|  | va_end(ap); | 
|  | for (fd = 3; fd < max; fd++) { | 
|  | for (i = 0; skip_fds[i] != fd && skip_fds[i] != -1; i++); | 
|  | if (skip_fds[i] == fd) | 
|  | continue; | 
|  | close(fd); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void __move_config(int veid, int action, const char *prefix) | 
|  | { | 
|  | char conf[PATH_LEN]; | 
|  | char newconf[PATH_LEN]; | 
|  |  | 
|  | snprintf(conf, sizeof(conf), VPS_CONF_DIR "%d.%s", veid, prefix); | 
|  | snprintf(newconf, sizeof(newconf), "%s." DESTR_PREFIX, conf); | 
|  | action == BACKUP ? rename(conf, newconf) : unlink(newconf); | 
|  | } | 
|  |  | 
|  | /* Renames or removes CT config and various CT scripts. | 
|  | */ | 
|  | int move_config(int veid, int action) | 
|  | { | 
|  | __move_config(veid, action, "conf"); | 
|  | __move_config(veid, action, MOUNT_PREFIX); | 
|  | __move_config(veid, action, UMOUNT_PREFIX); | 
|  | __move_config(veid, action, PRE_MOUNT_PREFIX); | 
|  | __move_config(veid, action, POST_UMOUNT_PREFIX); | 
|  | __move_config(veid, action, START_PREFIX); | 
|  | __move_config(veid, action, STOP_PREFIX); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void remove_names(envid_t veid) | 
|  | { | 
|  | char buf[STR_SIZE]; | 
|  | char content[STR_SIZE]; | 
|  | struct stat st; | 
|  | struct dirent *ep; | 
|  | DIR *dp; | 
|  | char *p; | 
|  | int r; | 
|  | envid_t id; | 
|  |  | 
|  | if (!(dp = opendir(VENAME_DIR))) | 
|  | return; | 
|  | while ((ep = readdir(dp))) { | 
|  | snprintf(buf, sizeof(buf), VENAME_DIR "/%s", ep->d_name); | 
|  | if (lstat(buf, &st)) | 
|  | continue; | 
|  | if (!S_ISLNK(st.st_mode)) | 
|  | continue; | 
|  | r = readlink(buf, content, sizeof(content) - 1); | 
|  | if (r < 0) | 
|  | continue; | 
|  | content[r] = 0; | 
|  | if ((p = strrchr(content, '/')) != NULL) | 
|  | p++; | 
|  | if (sscanf(p, "%d.conf", &id) == 1 && veid == id) | 
|  | unlink(buf); | 
|  | } | 
|  | closedir(dp); | 
|  | } | 
|  |  | 
|  | size_t vz_strlcat(char *dst, const char *src, size_t count) | 
|  | { | 
|  | size_t dsize = strlen(dst); | 
|  | size_t len = strlen(src); | 
|  | size_t res = dsize + len; | 
|  |  | 
|  | if (dsize >= count) | 
|  | return dsize; | 
|  |  | 
|  | dst += dsize; | 
|  | count -= dsize; | 
|  | if (len >= count) | 
|  | len = count - 1; | 
|  |  | 
|  | memcpy(dst, src, len); | 
|  | dst[len] = 0; | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | static int envid_sort_fn(const void *val1, const void *val2) | 
|  | { | 
|  | const envid_t *r1 = (const envid_t *)val1; | 
|  | const envid_t *r2 = (const envid_t *)val2; | 
|  |  | 
|  | return (*r1 - *r2); | 
|  | } | 
|  |  | 
|  | /** Returns a sorted array of all running CTs. | 
|  | * Caller needs to free() it after use | 
|  | */ | 
|  | int get_running_ve_list(envid_t **ves) | 
|  | { | 
|  | FILE *fp; | 
|  | int res; | 
|  | envid_t veid; | 
|  | int venum = 0; | 
|  | int ves_size = 256; | 
|  |  | 
|  |  | 
|  | *ves = malloc(ves_size * sizeof(envid_t)); | 
|  | if (*ves == NULL) | 
|  | return -ENOMEM; | 
|  |  | 
|  | if ((fp = fopen(PROCVEINFO, "r")) == NULL) { | 
|  | return -errno; | 
|  | } | 
|  | while (!feof(fp)) { | 
|  | res = fscanf(fp, "%d %*[^\n]", &veid); | 
|  | if (res != 1 || !veid) | 
|  | continue; | 
|  | if (venum >= ves_size) | 
|  | ves_size *= 2; | 
|  | *ves = realloc(*ves, ves_size * sizeof(envid_t)); | 
|  | if (*ves == NULL) | 
|  | { | 
|  | venum=-ENOMEM; | 
|  | goto out; | 
|  | } | 
|  | (*ves)[venum++] = veid; | 
|  | } | 
|  | qsort(*ves, venum, sizeof(envid_t), envid_sort_fn); | 
|  | out: | 
|  | fclose(fp); | 
|  | return venum; | 
|  | } | 
|  |  | 
|  | /* Searches for ve in velist */ | 
|  | int ve_in_list(envid_t *list, int size, envid_t ve) | 
|  | { | 
|  | return bsearch(&ve, list, size, sizeof(envid_t), | 
|  | envid_sort_fn) != NULL; | 
|  | } | 
|  |  | 
|  | const char* ubcstr(unsigned long bar, unsigned long lim) | 
|  | { | 
|  | static char str[64]; | 
|  | char *p = str; | 
|  | char *e = p + sizeof(str) - 1; | 
|  |  | 
|  | #define PRINT_UBC(val) \ | 
|  | if (val == LONG_MAX) \ | 
|  | p += snprintf(p, e - p, "unlimited"); \ | 
|  | else \ | 
|  | p += snprintf(p, e - p, "%lu", val) | 
|  |  | 
|  | PRINT_UBC(bar); | 
|  |  | 
|  | if (bar == lim) | 
|  | return str; | 
|  |  | 
|  | *p++=':'; | 
|  | PRINT_UBC(lim); | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | int is_vswap_mode(void) | 
|  | { | 
|  | return (access("/proc/vz/vswap", F_OK) == 0); | 
|  | } |