static int virLockManagerSanlockAddDisk(virLockManagerPtr lock, const char *name, size_t nparams, virLockManagerParamPtr params ATTRIBUTE_UNUSED, bool shared) { virLockManagerSanlockPrivatePtr priv = lock->privateData; int ret = -1; struct sanlk_resource *res = NULL; char *path = NULL; if (nparams) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unexpected lock parameters for disk resource")); return -1; } if (VIR_ALLOC_VAR(res, struct sanlk_disk, 1) < 0) { virReportOOMError(); goto cleanup; } res->flags = shared ? SANLK_RES_SHARED : 0; res->num_disks = 1; if (virLockManagerSanlockDiskLeaseName(name, res->name, SANLK_NAME_LEN) < 0) goto cleanup; if (virAsprintf(&path, "%s/%s", driver->autoDiskLeasePath, res->name) < 0) { virReportOOMError(); goto cleanup; } if (!virStrcpy(res->disks[0].path, path, SANLK_PATH_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Lease path '%s' exceeds %d characters"), path, SANLK_PATH_LEN); goto cleanup; } if (!virStrcpy(res->lockspace_name, VIR_LOCK_MANAGER_SANLOCK_AUTO_DISK_LOCKSPACE, SANLK_NAME_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Resource lockspace '%s' exceeds %d characters"), VIR_LOCK_MANAGER_SANLOCK_AUTO_DISK_LOCKSPACE, SANLK_NAME_LEN); goto cleanup; } priv->res_args[priv->res_count] = res; priv->res_count++; ret = 0; cleanup: if (ret == -1) VIR_FREE(res); VIR_FREE(path); return ret; }
static int virLockManagerSanlockAddLease(virLockManagerPtr lock, const char *name, size_t nparams, virLockManagerParamPtr params, bool shared) { virLockManagerSanlockPrivatePtr priv = lock->privateData; int ret = -1; struct sanlk_resource *res = NULL; int i; if (VIR_ALLOC_VAR(res, struct sanlk_disk, 1) < 0) { virReportOOMError(); goto cleanup; } res->flags = shared ? SANLK_RES_SHARED : 0; res->num_disks = 1; if (!virStrcpy(res->name, name, SANLK_NAME_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Resource name '%s' exceeds %d characters"), name, SANLK_NAME_LEN); goto cleanup; } for (i = 0; i < nparams; i++) { if (STREQ(params[i].key, "path")) { if (!virStrcpy(res->disks[0].path, params[i].value.str, SANLK_PATH_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Lease path '%s' exceeds %d characters"), params[i].value.str, SANLK_PATH_LEN); goto cleanup; } } else if (STREQ(params[i].key, "offset")) { res->disks[0].offset = params[i].value.ul; } else if (STREQ(params[i].key, "lockspace")) { if (!virStrcpy(res->lockspace_name, params[i].value.str, SANLK_NAME_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Resource lockspace '%s' exceeds %d characters"), params[i].value.str, SANLK_NAME_LEN); goto cleanup; } } } priv->res_args[priv->res_count] = res; priv->res_count++; ret = 0; cleanup: if (ret == -1) VIR_FREE(res); return ret; }
int virFDStreamConnectUNIX(virStreamPtr st, const char *path, bool abstract) { struct sockaddr_un sa; size_t i = 0; int timeout = 3; int ret; int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { virReportSystemError(errno, "%s", _("Unable to open UNIX socket")); goto error; } memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; if (abstract) { if (virStrcpy(sa.sun_path+1, path, sizeof(sa.sun_path)-1) == NULL) goto error; sa.sun_path[0] = '\0'; } else { if (virStrcpy(sa.sun_path, path, sizeof(sa.sun_path)) == NULL) goto error; } do { ret = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); if (ret == 0) break; if (errno == ENOENT || errno == ECONNREFUSED) { /* ENOENT : Socket may not have shown up yet * ECONNREFUSED : Leftover socket hasn't been removed yet */ continue; } goto error; } while ((++i <= timeout*5) && (usleep(.2 * 1000000) <= 0)); if (virFDStreamOpenInternal(st, fd, NULL, -1, 0) < 0) goto error; return 0; error: VIR_FORCE_CLOSE(fd); return -1; }
static int virLockManagerSanlockNew(virLockManagerPtr lock, unsigned int type, size_t nparams, virLockManagerParamPtr params, unsigned int flags) { virLockManagerParamPtr param; virLockManagerSanlockPrivatePtr priv; int i; virCheckFlags(0, -1); if (!driver) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Sanlock plugin is not initialized")); return -1; } if (type != VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unsupported object type %d"), type); return -1; } if (VIR_ALLOC(priv) < 0) { virReportOOMError(); return -1; } priv->flags = flags; for (i = 0; i < nparams; i++) { param = ¶ms[i]; if (STREQ(param->key, "uuid")) { memcpy(priv->vm_uuid, param->value.uuid, 16); } else if (STREQ(param->key, "name")) { if (!virStrcpy(priv->vm_name, param->value.str, SANLK_NAME_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Domain name '%s' exceeded %d characters"), param->value.str, SANLK_NAME_LEN); goto error; } } else if (STREQ(param->key, "pid")) { priv->vm_pid = param->value.ui; } else if (STREQ(param->key, "id")) { priv->vm_id = param->value.ui; } else if (STREQ(param->key, "uri")) { priv->vm_uri = param->value.cstr; } } lock->privateData = priv; return 0; error: VIR_FREE(priv); return -1; }
static int openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len) { char *conf_file; char *line = NULL; size_t line_size = 0; char *saveptr = NULL; char *uuidbuf; char *iden; FILE *fp; int retval = -1; if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0) return -1; fp = fopen(conf_file, "r"); if (fp == NULL) goto cleanup; while (1) { if (getline(&line, &line_size, fp) < 0) { if (feof(fp)) { /* EOF, UUID was not found */ uuidstr[0] = 0; break; } else { goto cleanup; } } iden = strtok_r(line, " ", &saveptr); uuidbuf = strtok_r(NULL, "\n", &saveptr); if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) { if (virStrcpy(uuidstr, uuidbuf, len) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid uuid %s"), uuidbuf); goto cleanup; } break; } } retval = 0; cleanup: VIR_FREE(line); VIR_FORCE_FCLOSE(fp); VIR_FREE(conf_file); return retval; }
/** * ifaceGetNthParent * * @ifindex : the index of the interface or -1 if ifname is given * @ifname : the name of the interface; ignored if ifindex is valid * @nthParent : the nth parent interface to get * @parent_ifindex : pointer to int * @parent_ifname : pointer to buffer of size IFNAMSIZ * @nth : the nth parent that is actually returned; if for example eth0.100 * was given and the 100th parent is to be returned, then eth0 will * most likely be returned with nth set to 1 since the chain does * not have more interfaces * * Get the nth parent interface of the given interface. 0 is the interface * itself. * * Return 0 on success, != 0 otherwise */ static int ifaceGetNthParent(int ifindex, const char *ifname, unsigned int nthParent, int *parent_ifindex, char *parent_ifname, unsigned int *nth) { int rc; struct nlattr *tb[IFLA_MAX + 1] = { NULL, }; char *recvbuf = NULL; bool end = false; unsigned int i = 0; *nth = 0; if (ifindex <= 0 && ifaceGetIndex(true, ifname, &ifindex) != 0) return 1; while (!end && i <= nthParent) { rc = link_dump(true, ifname, ifindex, tb, &recvbuf); if (rc) break; if (tb[IFLA_IFNAME]) { if (!virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]), IFNAMSIZ)) { macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", _("buffer for root interface name is too small")); VIR_FREE(recvbuf); return 1; } *parent_ifindex = ifindex; } if (tb[IFLA_LINK]) { ifindex = *(int *)RTA_DATA(tb[IFLA_LINK]); ifname = NULL; } else end = true; VIR_FREE(recvbuf); i++; } if (nth) *nth = i - 1; return rc; }
/* * Return new file path in malloced string created by * concatenating first and second function arguments. */ char * parallelsAddFileExt(const char *path, const char *ext) { char *new_path = NULL; size_t len = strlen(path) + strlen(ext) + 1; if (VIR_ALLOC_N(new_path, len) < 0) return NULL; if (!virStrcpy(new_path, path, len)) { VIR_FREE(new_path); return NULL; } strcat(new_path, ext); return new_path; }
/* * Return new file path in malloced string created by * concatenating first and second function arguments. */ char * parallelsAddFileExt(const char *path, const char *ext) { char *new_path = NULL; size_t len = strlen(path) + strlen(ext) + 1; if (VIR_ALLOC_N(new_path, len) < 0) { virReportOOMError(); return NULL; } if (!virStrcpy(new_path, path, len)) return NULL; strcat(new_path, ext); return new_path; }
static int virLockManagerSanlockAcquire(virLockManagerPtr lock, const char *state, unsigned int flags, virDomainLockFailureAction action, int *fd) { virLockManagerSanlockPrivatePtr priv = lock->privateData; struct sanlk_options *opt; struct sanlk_resource **res_args; int res_count; bool res_free = false; int sock = -1; int rv; int i; virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_RESTRICT | VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY, -1); if (priv->res_count == 0 && priv->hasRWDisks && driver->requireLeaseForDisks) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Read/write, exclusive access, disks were present, but no leases specified")); return -1; } if (VIR_ALLOC(opt) < 0) { virReportOOMError(); return -1; } if (!virStrcpy(opt->owner_name, priv->vm_name, SANLK_NAME_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Domain name '%s' exceeded %d characters"), priv->vm_name, SANLK_NAME_LEN); goto error; } if (state && STRNEQ(state, "")) { if ((rv = sanlock_state_to_args((char *)state, &res_count, &res_args)) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to parse lock state %s: error %d"), state, rv); else virReportSystemError(-rv, _("Unable to parse lock state %s"), state); goto error; } res_free = true; } else { res_args = priv->res_args; res_count = priv->res_count; } /* We only initialize 'sock' if we are in the real * child process and we need it to be inherited * * If sock==-1, then sanlock auto-open/closes a * temporary sock */ if (priv->vm_pid == getpid()) { VIR_DEBUG("Register sanlock %d", flags); if ((sock = sanlock_register()) < 0) { if (sock <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to open socket to sanlock daemon: error %d"), sock); else virReportSystemError(-sock, "%s", _("Failed to open socket to sanlock daemon")); goto error; } if (action != VIR_DOMAIN_LOCK_FAILURE_DEFAULT) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(priv->vm_uuid, uuidstr); if (virLockManagerSanlockRegisterKillscript(sock, priv->vm_uri, uuidstr, action) < 0) goto error; } } if (!(flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)) { VIR_DEBUG("Acquiring object %u", priv->res_count); if ((rv = sanlock_acquire(sock, priv->vm_pid, 0, priv->res_count, priv->res_args, opt)) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to acquire lock: error %d"), rv); else virReportSystemError(-rv, "%s", _("Failed to acquire lock")); goto error; } } VIR_FREE(opt); /* * We are *intentionally* "leaking" sock file descriptor * because we want it to be inherited by QEMU. When the * sock FD finally closes upon QEMU exit (or crash) then * sanlock will notice EOF and release the lock */ if (sock != -1 && virSetInherit(sock, true) < 0) goto error; if (flags & VIR_LOCK_MANAGER_ACQUIRE_RESTRICT) { if ((rv = sanlock_restrict(sock, SANLK_RESTRICT_ALL)) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to restrict process: error %d"), rv); else virReportSystemError(-rv, "%s", _("Failed to restrict process")); goto error; } } VIR_DEBUG("Acquire completed fd=%d", sock); if (res_free) { for (i = 0 ; i < res_count ; i++) { VIR_FREE(res_args[i]); } VIR_FREE(res_args); } if (fd) *fd = sock; return 0; error: if (res_free) { for (i = 0 ; i < res_count ; i++) { VIR_FREE(res_args[i]); } VIR_FREE(res_args); } VIR_FREE(opt); VIR_FORCE_CLOSE(sock); return -1; }
static int virLockManagerSanlockSetupLockspace(void) { int fd = -1; struct stat st; int rv; struct sanlk_lockspace ls; char *path = NULL; char *dir = NULL; int retries = LOCKSPACE_RETRIES; if (virAsprintf(&path, "%s/%s", driver->autoDiskLeasePath, VIR_LOCK_MANAGER_SANLOCK_AUTO_DISK_LOCKSPACE) < 0) { virReportOOMError(); goto error; } memcpy(ls.name, VIR_LOCK_MANAGER_SANLOCK_AUTO_DISK_LOCKSPACE, SANLK_NAME_LEN); ls.host_id = 0; /* Doesn't matter for initialization */ ls.flags = 0; if (!virStrcpy(ls.host_id_disk.path, path, SANLK_PATH_LEN)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Lockspace path '%s' exceeded %d characters"), path, SANLK_PATH_LEN); goto error; } ls.host_id_disk.offset = 0; /* Stage 1: Ensure the lockspace file exists on disk, has * space allocated for it and is initialized with lease */ if (stat(path, &st) < 0) { int perms = 0600; VIR_DEBUG("Lockspace %s does not yet exist", path); if (!(dir = mdir_name(path))) { virReportOOMError(); goto error; } if (stat(dir, &st) < 0 || !S_ISDIR(st.st_mode)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to create lockspace %s: parent directory" " does not exist or is not a directory"), path); goto error; } if (driver->group != -1) perms |= 0060; if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, perms)) < 0) { if (errno != EEXIST) { virReportSystemError(errno, _("Unable to create lockspace %s"), path); goto error; } VIR_DEBUG("Someone else just created lockspace %s", path); } else { /* chown() the path to make sure sanlock can access it */ if ((driver->user != -1 || driver->group != -1) && (fchown(fd, driver->user, driver->group) < 0)) { virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), path, (unsigned int) driver->user, (unsigned int) driver->group); goto error_unlink; } if ((rv = sanlock_align(&ls.host_id_disk)) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to query sector size %s: error %d"), path, rv); else virReportSystemError(-rv, _("Unable to query sector size %s"), path); goto error_unlink; } /* * Pre allocate enough data for 1 block of leases at preferred alignment */ if (safezero(fd, 0, rv) < 0) { virReportSystemError(errno, _("Unable to allocate lockspace %s"), path); goto error_unlink; } if (VIR_CLOSE(fd) < 0) { virReportSystemError(errno, _("Unable to save lockspace %s"), path); goto error_unlink; } if ((rv = sanlock_init(&ls, NULL, 0, 0)) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to initialize lockspace %s: error %d"), path, rv); else virReportSystemError(-rv, _("Unable to initialize lockspace %s"), path); goto error_unlink; } VIR_DEBUG("Lockspace %s has been initialized", path); } } else if (S_ISREG(st.st_mode)) { /* okay, the lease file exists. Check the permissions */ if (((driver->user != -1 && driver->user != st.st_uid) || (driver->group != -1 && driver->group != st.st_gid)) && (chown(path, driver->user, driver->group) < 0)) { virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), path, (unsigned int) driver->user, (unsigned int) driver->group); goto error; } if ((driver->group != -1 && (st.st_mode & 0060) != 0060) && chmod(path, 0660) < 0) { virReportSystemError(errno, _("cannot chmod '%s' to 0660"), path); goto error; } } ls.host_id = driver->hostID; /* Stage 2: Try to register the lockspace with the daemon. If the lockspace * is already registered, we should get EEXIST back in which case we can * just carry on with life. If EINPROGRESS is returned, we have two options: * either call a sanlock API that blocks us until lockspace changes state, * or we can fallback to polling. */ retry: if ((rv = sanlock_add_lockspace(&ls, 0)) < 0) { if (-rv == EINPROGRESS && --retries) { #ifdef HAVE_SANLOCK_INQ_LOCKSPACE /* we have this function which blocks until lockspace change the * state. It returns 0 if lockspace has been added, -ENOENT if it * hasn't. */ VIR_DEBUG("Inquiring lockspace"); if (sanlock_inq_lockspace(&ls, SANLK_INQ_WAIT) < 0) VIR_DEBUG("Unable to inquire lockspace"); #else /* fall back to polling */ VIR_DEBUG("Sleeping for %dms", LOCKSPACE_SLEEP); usleep(LOCKSPACE_SLEEP * 1000); #endif VIR_DEBUG("Retrying to add lockspace (left %d)", retries); goto retry; } if (-rv != EEXIST) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to add lockspace %s: error %d"), path, rv); else virReportSystemError(-rv, _("Unable to add lockspace %s"), path); goto error; } else { VIR_DEBUG("Lockspace %s is already registered", path); } } else { VIR_DEBUG("Lockspace %s has been registered", path); } VIR_FREE(path); VIR_FREE(dir); return 0; error_unlink: unlink(path); error: VIR_FORCE_CLOSE(fd); VIR_FREE(path); VIR_FREE(dir); return -1; }