Files
xen/tools/libs/light/libxl_linux.c
T
Juergen Gross 2419a159fb tools/libs/light: don't set errno to a negative value
Setting errno to a negative value makes no sense.

Fixes: e78e8b9bb6 ("libxl: Add interface for querying hypervisor about PCI topology")
Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
2022-04-22 20:39:34 +01:00

371 lines
10 KiB
C

/*
* Copyright (C) 2011
* Author Roger Pau Monne <roger.pau@entel.upc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* 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 Lesser General Public License for more details.
*/
#include "libxl_osdeps.h" /* must come before any other headers */
#include <sys/resource.h>
#include "libxl_internal.h"
/* Workarounds for Linux-specific lacks can go here: */
#ifndef CLONE_NEWIPC /* Available as of Linux 2.6.19 / glibc 2.8 */
# define CLONE_NEWIPC 0x08000000
#endif
int libxl__try_phy_backend(mode_t st_mode)
{
if (S_ISBLK(st_mode) || S_ISREG(st_mode)) {
return 1;
}
return 0;
}
char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
{
return libxl__devid_to_vdev(gc, devid);
}
/* Hotplug scripts helpers */
static char **get_hotplug_env(libxl__gc *gc,
char *script, libxl__device *dev)
{
const char *type = libxl__device_kind_to_string(dev->backend_kind);
char *be_path = libxl__device_backend_path(gc, dev);
char **env;
int nr = 0;
const int arraysize = 15;
GCNEW_ARRAY(env, arraysize);
env[nr++] = "script";
env[nr++] = script;
env[nr++] = "XENBUS_TYPE";
env[nr++] = (char *) type;
env[nr++] = "XENBUS_PATH";
env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
env[nr++] = "XENBUS_BASE_PATH";
env[nr++] = "backend";
if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
libxl_nic_type nictype;
char *gatewaydev;
gatewaydev = libxl__xs_read(gc, XBT_NULL,
GCSPRINTF("%s/%s", be_path, "gatewaydev"));
env[nr++] = "netdev";
env[nr++] = gatewaydev ? : "";
if (libxl__nic_type(gc, dev, &nictype)) {
LOGD(ERROR, dev->domid, "unable to get nictype");
return NULL;
}
switch (nictype) {
case LIBXL_NIC_TYPE_VIF_IOEMU:
env[nr++] = "INTERFACE";
env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
dev->devid,
LIBXL_NIC_TYPE_VIF_IOEMU);
/*
* We need to fall through because for PV_IOEMU nic types we need
* to execute both the vif and the tap hotplug script, and we
* don't know which one we are executing in this call, so provide
* both env variables.
*/
case LIBXL_NIC_TYPE_VIF:
env[nr++] = "vif";
env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
dev->devid,
LIBXL_NIC_TYPE_VIF);
break;
default:
return NULL;
}
}
env[nr++] = NULL;
assert(nr <= arraysize);
return env;
}
/* Hotplug scripts caller functions */
static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
char ***args, char ***env,
libxl__device_action action, int num_exec)
{
char *be_path = libxl__device_backend_path(gc, dev);
char *script;
int nr = 0, rc = 0;
libxl_nic_type nictype;
script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path,
"script"));
if (!script) {
LOGED(ERROR, dev->domid,
"unable to read script from %s", be_path);
rc = ERROR_FAIL;
goto out;
}
rc = libxl__nic_type(gc, dev, &nictype);
if (rc) {
LOGD(ERROR, dev->domid, "error when fetching nic type");
rc = ERROR_FAIL;
goto out;
}
if (nictype == LIBXL_NIC_TYPE_VIF && num_exec != 0) {
rc = 0;
goto out;
}
*env = get_hotplug_env(gc, script, dev);
if (!*env) {
rc = ERROR_FAIL;
goto out;
}
const int arraysize = 4;
GCNEW_ARRAY(*args, arraysize);
(*args)[nr++] = script;
if (nictype == LIBXL_NIC_TYPE_VIF_IOEMU && num_exec) {
(*args)[nr++] = (char *) libxl__device_action_to_string(action);
(*args)[nr++] = "type_if=tap";
(*args)[nr++] = NULL;
} else {
(*args)[nr++] = action == LIBXL__DEVICE_ACTION_ADD ? "online" :
"offline";
(*args)[nr++] = "type_if=vif";
(*args)[nr++] = NULL;
}
assert(nr == arraysize);
rc = 1;
out:
return rc;
}
static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
char ***args, char ***env,
libxl__device_action action)
{
char *be_path = libxl__device_backend_path(gc, dev);
char *script;
int nr = 0, rc = 0;
script = libxl__xs_read(gc, XBT_NULL,
GCSPRINTF("%s/%s", be_path, "script"));
if (!script) {
LOGEVD(ERROR, errno, dev->domid,
"unable to read script from %s", be_path);
rc = ERROR_FAIL;
goto error;
}
*env = get_hotplug_env(gc, script, dev);
if (!*env) {
LOGD(ERROR, dev->domid, "Failed to get hotplug environment");
rc = ERROR_FAIL;
goto error;
}
const int arraysize = 3;
GCNEW_ARRAY(*args, arraysize);
(*args)[nr++] = script;
(*args)[nr++] = (char *) libxl__device_action_to_string(action);
(*args)[nr++] = NULL;
assert(nr == arraysize);
LOGD(DEBUG, dev->domid, "Args and environment ready");
rc = 1;
error:
return rc;
}
int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
char ***args, char ***env,
libxl__device_action action,
int num_exec)
{
int rc;
switch (dev->backend_kind) {
case LIBXL__DEVICE_KIND_VBD:
if (num_exec != 0) {
LOGD(DEBUG, dev->domid,
"num_exec %d, not running hotplug scripts", num_exec);
rc = 0;
goto out;
}
rc = libxl__hotplug_disk(gc, dev, args, env, action);
break;
case LIBXL__DEVICE_KIND_VIF:
/*
* If domain has a stubdom we don't have to execute hotplug scripts
* for emulated interfaces
*/
if ((num_exec > 1) ||
(libxl_get_stubdom_id(CTX, dev->domid) && num_exec)) {
LOGD(DEBUG, dev->domid,
"num_exec %d, not running hotplug scripts", num_exec);
rc = 0;
goto out;
}
rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
break;
default:
/* No need to execute any hotplug scripts */
LOGD(DEBUG, dev->domid,
"backend_kind %d, no need to execute scripts", dev->backend_kind);
rc = 0;
break;
}
out:
return rc;
}
int libxl__pci_numdevs(libxl__gc *gc)
{
DIR *dir;
struct dirent *entry;
int num_devs = 0;
dir = opendir("/sys/bus/pci/devices");
if (!dir) {
LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
return ERROR_FAIL;
}
while ((entry = readdir(dir))) {
if (entry->d_name[0] == '.')
continue;
num_devs++;
}
closedir(dir);
return num_devs;
}
int libxl__pci_topology_init(libxl__gc *gc,
physdev_pci_device_t *devs,
int num_devs)
{
DIR *dir;
struct dirent *entry;
int i, err = 0;
dir = opendir("/sys/bus/pci/devices");
if (!dir) {
LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
return ERROR_FAIL;
}
i = 0;
while ((entry = readdir(dir))) {
unsigned int dom, bus, dev, func;
if (entry->d_name[0] == '.')
continue;
if (i == num_devs) {
LOG(ERROR, "Too many devices");
err = ERROR_FAIL;
errno = ENOSPC;
goto out;
}
if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4) {
LOGE(ERROR, "Error processing /sys/bus/pci/devices");
err = ERROR_FAIL;
goto out;
}
devs[i].seg = dom;
devs[i].bus = bus;
devs[i].devfn = ((dev & 0x1f) << 3) | (func & 7);
i++;
}
out:
closedir(dir);
return err;
}
static struct {
int resource;
rlim_t limit;
} rlimits[] = {
#define RLIMIT_ENTRY(r, l) \
{ .resource = r, .limit = l }
/* Big enough for log files, not big enough for a DoS */
RLIMIT_ENTRY(RLIMIT_FSIZE, 256*1024),
/* Shouldn't need any of these */
RLIMIT_ENTRY(RLIMIT_CORE, 0),
RLIMIT_ENTRY(RLIMIT_MSGQUEUE, 0),
RLIMIT_ENTRY(RLIMIT_LOCKS, 0),
RLIMIT_ENTRY(RLIMIT_MEMLOCK, 0),
/* End-of-list marker */
RLIMIT_ENTRY(RLIMIT_NLIMITS, 0),
#undef RLIMIT_ENTRY
};
int libxl__local_dm_preexec_restrict(libxl__gc *gc)
{
int r;
unsigned i;
/* Unshare mount and IPC namespaces. These are unused by QEMU. */
r = unshare(CLONE_NEWNS | CLONE_NEWIPC);
if (r) {
LOGE(ERROR, "libxl: unshare Mount and IPC namespace failed");
return ERROR_FAIL;
}
/* Set various "easy" rlimits */
for (i = 0; rlimits[i].resource != RLIMIT_NLIMITS; i++) {
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = rlimits[i].limit;
r = setrlimit(rlimits[i].resource, &rlim);
if (r < 0) {
LOGE(ERROR, "Setting rlimit %d to %llu failed\n",
rlimits[i].resource,
(unsigned long long)rlimits[i].limit);
return ERROR_FAIL;
}
}
return 0;
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/