Files
mirror_zfs/lib/libzfs/os/linux/libzfs_util_os.c
T

313 lines
7.6 KiB
C
Raw Normal View History

2025-01-04 11:04:27 +11:00
// SPDX-License-Identifier: CDDL-1.0
2019-10-03 10:33:16 -07:00
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2022-07-11 23:16:13 +02:00
* or https://opensource.org/licenses/CDDL-1.0.
2019-10-03 10:33:16 -07:00
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
2021-02-21 10:19:43 -06:00
/*
* Copyright (c) 2021 Klara, Inc.
*/
2019-10-03 10:33:16 -07:00
2022-04-14 23:30:41 +02:00
#include <alloca.h>
2019-10-03 10:33:16 -07:00
#include <errno.h>
#include <fcntl.h>
#include <libintl.h>
2022-04-14 23:30:41 +02:00
#include <math.h>
#include <poll.h>
2019-10-03 10:33:16 -07:00
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
2022-04-14 23:30:41 +02:00
#include <sys/inotify.h>
2019-10-03 10:33:16 -07:00
#include <sys/mntent.h>
2022-04-14 23:30:41 +02:00
#include <sys/mnttab.h>
#include <sys/stat.h>
#include <sys/timerfd.h>
2019-10-03 10:33:16 -07:00
#include <sys/types.h>
#include <sys/wait.h>
2022-04-14 23:30:41 +02:00
#include <unistd.h>
2019-10-03 10:33:16 -07:00
#include <libzfs.h>
#include <libzfs_core.h>
2021-05-15 13:00:05 +02:00
#include "../../libzfs_impl.h"
2019-10-03 10:33:16 -07:00
#include "zfs_prop.h"
#include <libzutil.h>
2020-02-12 16:00:19 -05:00
#include <sys/zfs_sysfs.h>
2019-10-03 10:33:16 -07:00
#define ZDIFF_SHARESDIR "/.zfs/shares/"
const char *
libzfs_error_init(int error)
{
switch (error) {
case ENXIO:
return (dgettext(TEXT_DOMAIN, "The ZFS modules are not "
2022-04-14 23:30:41 +02:00
"loaded.\nTry running 'modprobe zfs' as root "
2019-10-03 10:33:16 -07:00
"to load them."));
case ENOENT:
return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
"are required.\nTry running 'udevadm trigger' and 'mount "
"-t proc proc /proc' as root."));
case ENOEXEC:
return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
2022-04-14 23:30:41 +02:00
"auto-loaded.\nTry running 'modprobe zfs' as "
2019-10-03 10:33:16 -07:00
"root to manually load them."));
case EACCES:
return (dgettext(TEXT_DOMAIN, "Permission denied the "
"ZFS utilities must be run as root."));
default:
return (dgettext(TEXT_DOMAIN, "Failed to initialize the "
"libzfs library."));
}
}
static int
in_container(void)
{
char buffer[4096];
ssize_t count;
int fd;
if (access("/run/systemd/container", R_OK) == 0)
return (1);
fd = open("/proc/1/cgroup", O_RDONLY);
if (fd == -1)
return (0);
count = read(fd, buffer, sizeof (buffer) - 1);
close(fd);
if (count <= 0)
return (0);
buffer[count] = '\0';
if (strstr(buffer, "docker") ||
strstr(buffer, "containerd") ||
strstr(buffer, "kubepods") ||
strstr(buffer, "lxc")) {
return (1);
}
return (0);
}
2019-10-03 10:33:16 -07:00
/*
2022-04-14 23:30:41 +02:00
* zfs(4) is loaded by udev if there's a fstype=zfs device present,
* but if there isn't, load them automatically;
* always wait for ZFS_DEV to appear via udev.
2019-10-03 10:33:16 -07:00
*
* Environment variables:
2022-04-14 23:30:41 +02:00
* - ZFS_MODULE_TIMEOUT="<seconds>" - Seconds to wait for ZFS_DEV,
* defaults to 10, max. 10 min.
2019-10-03 10:33:16 -07:00
*/
2022-04-14 23:30:41 +02:00
int
libzfs_load_module(void)
2019-10-03 10:33:16 -07:00
{
2022-04-14 23:30:41 +02:00
if (access(ZFS_DEV, F_OK) == 0)
return (0);
2019-10-03 10:33:16 -07:00
2022-04-14 23:30:41 +02:00
if (access(ZFS_SYSFS_DIR, F_OK) != 0) {
2022-04-19 20:38:30 +02:00
char *argv[] = {(char *)"modprobe", (char *)"zfs", NULL};
2022-04-14 23:30:41 +02:00
if (libzfs_run_process("modprobe", argv, 0))
return (ENOEXEC);
2019-10-03 10:33:16 -07:00
2022-04-14 23:30:41 +02:00
if (access(ZFS_SYSFS_DIR, F_OK) != 0)
2019-10-03 10:33:16 -07:00
return (ENXIO);
}
2022-04-14 23:30:41 +02:00
const char *timeout_str = getenv("ZFS_MODULE_TIMEOUT");
int seconds = 10;
/* Set timeout to zero if inside of a container */
if (in_container())
seconds = 0;
2022-04-14 23:30:41 +02:00
if (timeout_str)
seconds = MIN(strtol(timeout_str, NULL, 0), 600);
struct itimerspec timeout = {.it_value.tv_sec = MAX(seconds, 0)};
int ino = inotify_init1(IN_CLOEXEC);
if (ino == -1)
return (ENOENT);
inotify_add_watch(ino, ZFS_DEVDIR, IN_CREATE);
if (access(ZFS_DEV, F_OK) == 0) {
close(ino);
return (0);
} else if (seconds == 0) {
close(ino);
return (ENOENT);
2019-10-03 10:33:16 -07:00
}
2022-04-14 23:30:41 +02:00
size_t evsz = sizeof (struct inotify_event) + NAME_MAX + 1;
struct inotify_event *ev = alloca(evsz);
2019-10-03 10:33:16 -07:00
2022-04-14 23:30:41 +02:00
int tout = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (tout == -1) {
close(ino);
return (ENOENT);
}
timerfd_settime(tout, 0, &timeout, NULL);
int ret = ENOENT;
struct pollfd pfds[] = {
{.fd = ino, .events = POLLIN},
{.fd = tout, .events = POLLIN},
};
while (poll(pfds, ARRAY_SIZE(pfds), -1) != -1) {
if (pfds[0].revents & POLLIN) {
verify(read(ino, ev, evsz) >
sizeof (struct inotify_event));
2022-09-27 19:47:24 -04:00
if (strncmp(ev->name, &ZFS_DEV[sizeof (ZFS_DEVDIR)],
ev->len) == 0) {
2022-04-14 23:30:41 +02:00
ret = 0;
break;
}
}
if (pfds[1].revents & POLLIN)
break;
}
close(tout);
close(ino);
return (ret);
2019-10-03 10:33:16 -07:00
}
int
find_shares_object(differ_info_t *di)
{
char fullpath[MAXPATHLEN];
struct stat64 sb = { 0 };
(void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
(void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
if (stat64(fullpath, &sb) != 0) {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
}
di->shares = (uint64_t)sb.st_ino;
return (0);
}
2020-02-12 16:00:19 -05:00
int
zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
{
2021-12-12 15:38:17 +01:00
(void) hdl, (void) snaps;
return (0);
}
2020-02-12 16:00:19 -05:00
/*
* Return allocated loaded module version, or NULL on error (with errno set)
2020-02-12 16:00:19 -05:00
*/
char *
zfs_version_kernel(void)
2020-02-12 16:00:19 -05:00
{
FILE *f = fopen(ZFS_SYSFS_DIR "/version", "re");
if (f == NULL)
return (NULL);
char *ret = NULL;
size_t l;
ssize_t read;
if ((read = getline(&ret, &l, f)) == -1) {
int err = errno;
fclose(f);
errno = err;
return (NULL);
2020-02-12 16:00:19 -05:00
}
fclose(f);
if (ret[read - 1] == '\n')
ret[read - 1] = '\0';
return (ret);
2020-02-12 16:00:19 -05:00
}
2021-02-21 10:19:43 -06:00
/*
* Add or delete the given filesystem to/from the given user namespace.
*/
int
zfs_userns(zfs_handle_t *zhp, const char *nspath, int attach)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
zfs_cmd_t zc = {"\0"};
char errbuf[1024];
unsigned long cmd;
int ret;
if (attach) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot add '%s' to namespace"),
zhp->zfs_name);
} else {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot remove '%s' from namespace"),
zhp->zfs_name);
}
switch (zhp->zfs_type) {
case ZFS_TYPE_VOLUME:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"volumes can not be namespaced"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_SNAPSHOT:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"snapshots can not be namespaced"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_BOOKMARK:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"bookmarks can not be namespaced"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_VDEV:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"vdevs can not be namespaced"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_INVALID:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid zfs_type_t: ZFS_TYPE_INVALID"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_POOL:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pools can not be namespaced"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_FILESYSTEM:
break;
2021-02-21 10:19:43 -06:00
}
assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
zc.zc_objset_type = DMU_OST_ZFS;
zc.zc_cleanup_fd = open(nspath, O_RDONLY);
if (zc.zc_cleanup_fd < 0) {
return (zfs_error(hdl, EZFS_NOT_USER_NAMESPACE, errbuf));
}
cmd = attach ? ZFS_IOC_USERNS_ATTACH : ZFS_IOC_USERNS_DETACH;
if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
zfs_standard_error(hdl, errno, errbuf);
(void) close(zc.zc_cleanup_fd);
2021-02-21 10:19:43 -06:00
return (ret);
}