Repository: opencontainers/runc
File: libcontainer/nsenter/nsexec.c (C)

Code before:
			str = strappend(str, ns->name);
		}
	}
	return str ? : strdup("");
}

static void __close_namespaces(nsset_t to_join, nsset_t joined, struct namespace_t *ns_list, size_t ns_len)
{
	/* We expect to have joined every namespace. */
	nsset_t failed_to_join = to_join & ~joined;

	/* Double-check that we used up (and thus joined) all of the nsfds. */
	for (size_t i = 0; i < ns_len; i++) {
		struct namespace_t *ns = &ns_list[i];
		int type = nstype(ns->type);

		if (ns->fd < 0)
			continue;

		failed_to_join |= type;
		write_log(FATAL, "failed to setns(%#x) into %s namespace (with path %s): %s",
			  type, ns->type, ns->path, strerror(EPERM));
		close(ns->fd);
		ns->fd = -1;
	}

	/* Make sure we joined the namespaces we planned to. */
	if (failed_to_join)
		bail("failed to join {%s} namespaces: %s", nsset_to_str(failed_to_join), strerror(EPERM));

	free(ns_list);
}

void join_namespaces(char *nsspec)
{
	nsset_t to_join = 0, joined = 0;
	struct namespace_t *ns_list;
	size_t ns_len;

	/*
	 * We have to open the file descriptors first, since after we join the
	 * mnt or user namespaces we might no longer be able to access the
	 * paths.
	 */
	to_join = __open_namespaces(nsspec, &ns_list, &ns_len);

	/*
	 * We first try to join all non-userns namespaces to join any namespaces
	 * that we might not be able to join once we switch credentials to the
	 * container's userns. We then join the user namespace, and then try to
	 * join any remaining namespaces (this last step is needed for rootless

Review comment (suggestion):
nit: `bail` appends `: %m` to the message printed so maybe instead of `: %s", ... strerror(EPERM)` you can just assign `errno = EPERM` before calling it.

Otherwise we'll end up with something like `... namespaces: Operation not permitted: Success` which is somewhat confusing.

Code after:
	return str ? : strdup("");
}

static void __close_namespaces(nsset_t to_join, nsset_t joined, struct namespace_t *ns_list, size_t ns_len)
{
	/* We expect to have joined every namespace. */
	nsset_t failed_to_join = to_join & ~joined;

	/* Double-check that we used up (and thus joined) all of the nsfds. */
	for (size_t i = 0; i < ns_len; i++) {
		struct namespace_t *ns = &ns_list[i];
		int type = nstype(ns->type);

		if (ns->fd < 0)
			continue;

		failed_to_join |= type;
		write_log(FATAL, "failed to setns(%#x) into %s namespace (with path %s): %s",
			  type, ns->type, ns->path, strerror(EPERM));
		close(ns->fd);
		ns->fd = -1;
	}

	/* Make sure we joined the namespaces we planned to. */
	if (failed_to_join)
		bail("failed to join {%s} namespaces: %s", nsset_to_str(failed_to_join), strerror(EPERM));

	free(ns_list);
}

void join_namespaces(char *nsspec)
{
	nsset_t to_join = 0, joined = 0;
	struct namespace_t *ns_list;
	size_t ns_len;

	/*
	 * We have to open the file descriptors first, since after we join the
	 * mnt or user namespaces we might no longer be able to access the
	 * paths.
	 */
	to_join = __open_namespaces(nsspec, &ns_list, &ns_len);

	/*
	 * We first try to join all non-userns namespaces to join any namespaces
	 * that we might not be able to join once we switch credentials to the
	 * container's userns. We then join the user namespace, and then try to
	 * join any remaining namespaces (this last step is needed for rootless
	 * containers -- we don't get setns(2) permissions until we join the userns
	 * and get CAP_SYS_ADMIN).
	 *