Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : 3 : #include <fcntl.h> 4 : #include <linux/magic.h> 5 : #include <unistd.h> 6 : 7 : #include "alloc-util.h" 8 : #include "fd-util.h" 9 : #include "macro.h" 10 : #include "missing.h" 11 : #include "mountpoint-util.h" 12 : #include "namespace-util.h" 13 : #include "path-util.h" 14 : #include "stat-util.h" 15 : #include "tmpfile-util.h" 16 : 17 1 : static void test_files_same(void) { 18 1 : _cleanup_close_ int fd = -1; 19 1 : char name[] = "/tmp/test-files_same.XXXXXX"; 20 1 : char name_alias[] = "/tmp/test-files_same.alias"; 21 : 22 1 : fd = mkostemp_safe(name); 23 1 : assert_se(fd >= 0); 24 1 : assert_se(symlink(name, name_alias) >= 0); 25 : 26 1 : assert_se(files_same(name, name, 0)); 27 1 : assert_se(files_same(name, name, AT_SYMLINK_NOFOLLOW)); 28 1 : assert_se(files_same(name, name_alias, 0)); 29 1 : assert_se(!files_same(name, name_alias, AT_SYMLINK_NOFOLLOW)); 30 : 31 1 : unlink(name); 32 1 : unlink(name_alias); 33 1 : } 34 : 35 1 : static void test_is_symlink(void) { 36 1 : char name[] = "/tmp/test-is_symlink.XXXXXX"; 37 1 : char name_link[] = "/tmp/test-is_symlink.link"; 38 1 : _cleanup_close_ int fd = -1; 39 : 40 1 : fd = mkostemp_safe(name); 41 1 : assert_se(fd >= 0); 42 1 : assert_se(symlink(name, name_link) >= 0); 43 : 44 1 : assert_se(is_symlink(name) == 0); 45 1 : assert_se(is_symlink(name_link) == 1); 46 1 : assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); 47 : 48 1 : unlink(name); 49 1 : unlink(name_link); 50 1 : } 51 : 52 1 : static void test_path_is_fs_type(void) { 53 : /* run might not be a mount point in build chroots */ 54 1 : if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) { 55 1 : assert_se(path_is_fs_type("/run", TMPFS_MAGIC) > 0); 56 1 : assert_se(path_is_fs_type("/run", BTRFS_SUPER_MAGIC) == 0); 57 : } 58 1 : assert_se(path_is_fs_type("/proc", PROC_SUPER_MAGIC) > 0); 59 1 : assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0); 60 1 : assert_se(path_is_fs_type("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT); 61 1 : } 62 : 63 1 : static void test_path_is_temporary_fs(void) { 64 : /* run might not be a mount point in build chroots */ 65 1 : if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) 66 1 : assert_se(path_is_temporary_fs("/run") > 0); 67 1 : assert_se(path_is_temporary_fs("/proc") == 0); 68 1 : assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT); 69 1 : } 70 : 71 1 : static void test_fd_is_network_ns(void) { 72 1 : _cleanup_close_ int fd = -1; 73 1 : assert_se(fd_is_network_ns(STDIN_FILENO) == 0); 74 1 : assert_se(fd_is_network_ns(STDERR_FILENO) == 0); 75 1 : assert_se(fd_is_network_ns(STDOUT_FILENO) == 0); 76 : 77 1 : assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0); 78 1 : assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN)); 79 1 : fd = safe_close(fd); 80 : 81 1 : assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); 82 1 : assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN)); 83 1 : } 84 : 85 1 : static void test_device_major_minor_valid(void) { 86 : /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */ 87 : assert_cc(sizeof(dev_t) == sizeof(uint64_t)); 88 : 89 1 : assert_se(DEVICE_MAJOR_VALID(0U)); 90 1 : assert_se(DEVICE_MINOR_VALID(0U)); 91 : 92 1 : assert_se(DEVICE_MAJOR_VALID(1U)); 93 1 : assert_se(DEVICE_MINOR_VALID(1U)); 94 : 95 1 : assert_se(!DEVICE_MAJOR_VALID(-1U)); 96 1 : assert_se(!DEVICE_MINOR_VALID(-1U)); 97 : 98 1 : assert_se(DEVICE_MAJOR_VALID(1U << 10)); 99 1 : assert_se(DEVICE_MINOR_VALID(1U << 10)); 100 : 101 1 : assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1)); 102 1 : assert_se(DEVICE_MINOR_VALID((1U << 20) - 1)); 103 : 104 1 : assert_se(!DEVICE_MAJOR_VALID((1U << 12))); 105 1 : assert_se(!DEVICE_MINOR_VALID((1U << 20))); 106 : 107 1 : assert_se(!DEVICE_MAJOR_VALID(1U << 25)); 108 1 : assert_se(!DEVICE_MINOR_VALID(1U << 25)); 109 : 110 1 : assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX)); 111 1 : assert_se(!DEVICE_MINOR_VALID(UINT32_MAX)); 112 : 113 1 : assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX)); 114 1 : assert_se(!DEVICE_MINOR_VALID(UINT64_MAX)); 115 : 116 1 : assert_se(DEVICE_MAJOR_VALID(major(0))); 117 1 : assert_se(DEVICE_MINOR_VALID(minor(0))); 118 1 : } 119 : 120 6 : static void test_device_path_make_canonical_one(const char *path) { 121 6 : _cleanup_free_ char *resolved = NULL, *raw = NULL; 122 : struct stat st; 123 : dev_t devno; 124 : mode_t mode; 125 : int r; 126 : 127 6 : assert_se(stat(path, &st) >= 0); 128 6 : r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved); 129 6 : if (r == -ENOENT) /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we 130 : * run in a container or so? */ 131 0 : return; 132 : 133 6 : assert_se(r >= 0); 134 6 : assert_se(path_equal(path, resolved)); 135 : 136 6 : assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0); 137 6 : assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0); 138 : 139 6 : assert_se(st.st_rdev == devno); 140 6 : assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT)); 141 : } 142 : 143 1 : static void test_device_path_make_canonical(void) { 144 : 145 1 : test_device_path_make_canonical_one("/dev/null"); 146 1 : test_device_path_make_canonical_one("/dev/zero"); 147 1 : test_device_path_make_canonical_one("/dev/full"); 148 1 : test_device_path_make_canonical_one("/dev/random"); 149 1 : test_device_path_make_canonical_one("/dev/urandom"); 150 1 : test_device_path_make_canonical_one("/dev/tty"); 151 : 152 1 : if (is_device_node("/run/systemd/inaccessible/chr") > 0) { 153 0 : test_device_path_make_canonical_one("/run/systemd/inaccessible/chr"); 154 0 : test_device_path_make_canonical_one("/run/systemd/inaccessible/blk"); 155 : } 156 1 : } 157 : 158 1 : int main(int argc, char *argv[]) { 159 1 : test_files_same(); 160 1 : test_is_symlink(); 161 1 : test_path_is_fs_type(); 162 1 : test_path_is_temporary_fs(); 163 1 : test_fd_is_network_ns(); 164 1 : test_device_major_minor_valid(); 165 1 : test_device_path_make_canonical(); 166 : 167 1 : return 0; 168 : }