LCOV - code coverage report
Current view: top level - basic - stat-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 133 185 71.9 %
Date: 2019-08-22 15:41:25 Functions: 22 25 88.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <dirent.h>
       4             : #include <errno.h>
       5             : #include <fcntl.h>
       6             : #include <linux/magic.h>
       7             : #include <sched.h>
       8             : #include <sys/stat.h>
       9             : #include <sys/statvfs.h>
      10             : #include <sys/types.h>
      11             : #include <unistd.h>
      12             : 
      13             : #include "alloc-util.h"
      14             : #include "dirent-util.h"
      15             : #include "fd-util.h"
      16             : #include "fs-util.h"
      17             : #include "macro.h"
      18             : #include "missing.h"
      19             : #include "parse-util.h"
      20             : #include "stat-util.h"
      21             : #include "string-util.h"
      22             : 
      23          28 : int is_symlink(const char *path) {
      24             :         struct stat info;
      25             : 
      26          28 :         assert(path);
      27             : 
      28          28 :         if (lstat(path, &info) < 0)
      29          23 :                 return -errno;
      30             : 
      31           5 :         return !!S_ISLNK(info.st_mode);
      32             : }
      33             : 
      34        1657 : int is_dir(const char* path, bool follow) {
      35             :         struct stat st;
      36             :         int r;
      37             : 
      38        1657 :         assert(path);
      39             : 
      40        1657 :         if (follow)
      41         463 :                 r = stat(path, &st);
      42             :         else
      43        1194 :                 r = lstat(path, &st);
      44        1657 :         if (r < 0)
      45          56 :                 return -errno;
      46             : 
      47        1601 :         return !!S_ISDIR(st.st_mode);
      48             : }
      49             : 
      50           0 : int is_dir_fd(int fd) {
      51             :         struct stat st;
      52             : 
      53           0 :         if (fstat(fd, &st) < 0)
      54           0 :                 return -errno;
      55             : 
      56           0 :         return !!S_ISDIR(st.st_mode);
      57             : }
      58             : 
      59           1 : int is_device_node(const char *path) {
      60             :         struct stat info;
      61             : 
      62           1 :         assert(path);
      63             : 
      64           1 :         if (lstat(path, &info) < 0)
      65           1 :                 return -errno;
      66             : 
      67           0 :         return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
      68             : }
      69             : 
      70          20 : int dir_is_empty_at(int dir_fd, const char *path) {
      71          20 :         _cleanup_close_ int fd = -1;
      72          20 :         _cleanup_closedir_ DIR *d = NULL;
      73             :         struct dirent *de;
      74             : 
      75          20 :         if (path)
      76          20 :                 fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
      77             :         else
      78           0 :                 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
      79          20 :         if (fd < 0)
      80           2 :                 return -errno;
      81             : 
      82          18 :         d = fdopendir(fd);
      83          18 :         if (!d)
      84           0 :                 return -errno;
      85          18 :         fd = -1;
      86             : 
      87          26 :         FOREACH_DIRENT(de, d, return -errno)
      88          16 :                 return 0;
      89             : 
      90           2 :         return 1;
      91             : }
      92             : 
      93        1827 : bool null_or_empty(struct stat *st) {
      94        1827 :         assert(st);
      95             : 
      96        1827 :         if (S_ISREG(st->st_mode) && st->st_size <= 0)
      97           6 :                 return true;
      98             : 
      99             :         /* We don't want to hardcode the major/minor of /dev/null,
     100             :          * hence we do a simpler "is this a device node?" check. */
     101             : 
     102        1821 :         if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
     103           9 :                 return true;
     104             : 
     105        1812 :         return false;
     106             : }
     107             : 
     108         847 : int null_or_empty_path(const char *fn) {
     109             :         struct stat st;
     110             : 
     111         847 :         assert(fn);
     112             : 
     113         847 :         if (stat(fn, &st) < 0)
     114           0 :                 return -errno;
     115             : 
     116         847 :         return null_or_empty(&st);
     117             : }
     118             : 
     119           3 : int null_or_empty_fd(int fd) {
     120             :         struct stat st;
     121             : 
     122           3 :         assert(fd >= 0);
     123             : 
     124           3 :         if (fstat(fd, &st) < 0)
     125           0 :                 return -errno;
     126             : 
     127           3 :         return null_or_empty(&st);
     128             : }
     129             : 
     130           8 : int path_is_read_only_fs(const char *path) {
     131             :         struct statvfs st;
     132             : 
     133           8 :         assert(path);
     134             : 
     135           8 :         if (statvfs(path, &st) < 0)
     136           0 :                 return -errno;
     137             : 
     138           8 :         if (st.f_flag & ST_RDONLY)
     139           0 :                 return true;
     140             : 
     141             :         /* On NFS, statvfs() might not reflect whether we can actually
     142             :          * write to the remote share. Let's try again with
     143             :          * access(W_OK) which is more reliable, at least sometimes. */
     144           8 :         if (access(path, W_OK) < 0 && errno == EROFS)
     145           0 :                 return true;
     146             : 
     147           8 :         return false;
     148             : }
     149             : 
     150         181 : int files_same(const char *filea, const char *fileb, int flags) {
     151             :         struct stat a, b;
     152             : 
     153         181 :         assert(filea);
     154         181 :         assert(fileb);
     155             : 
     156         181 :         if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
     157          90 :                 return -errno;
     158             : 
     159          91 :         if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
     160           4 :                 return -errno;
     161             : 
     162         118 :         return a.st_dev == b.st_dev &&
     163          31 :                a.st_ino == b.st_ino;
     164             : }
     165             : 
     166       81313 : bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
     167       81313 :         assert(s);
     168             :         assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
     169             : 
     170       81313 :         return F_TYPE_EQUAL(s->f_type, magic_value);
     171             : }
     172             : 
     173          58 : int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
     174             :         struct statfs s;
     175             : 
     176          58 :         if (fstatfs(fd, &s) < 0)
     177           0 :                 return -errno;
     178             : 
     179          58 :         return is_fs_type(&s, magic_value);
     180             : }
     181             : 
     182           5 : int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
     183           5 :         _cleanup_close_ int fd = -1;
     184             : 
     185           5 :         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
     186           5 :         if (fd < 0)
     187           1 :                 return -errno;
     188             : 
     189           4 :         return fd_is_fs_type(fd, magic_value);
     190             : }
     191             : 
     192           4 : bool is_temporary_fs(const struct statfs *s) {
     193           5 :         return is_fs_type(s, TMPFS_MAGIC) ||
     194           1 :                 is_fs_type(s, RAMFS_MAGIC);
     195             : }
     196             : 
     197       10155 : bool is_network_fs(const struct statfs *s) {
     198       20310 :         return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
     199       10155 :                 is_fs_type(s, CODA_SUPER_MAGIC) ||
     200       10155 :                 is_fs_type(s, NCP_SUPER_MAGIC) ||
     201       10155 :                 is_fs_type(s, NFS_SUPER_MAGIC) ||
     202       10155 :                 is_fs_type(s, SMB_SUPER_MAGIC) ||
     203       10155 :                 is_fs_type(s, V9FS_MAGIC) ||
     204       30465 :                 is_fs_type(s, AFS_SUPER_MAGIC) ||
     205       10155 :                 is_fs_type(s, OCFS2_SUPER_MAGIC);
     206             : }
     207             : 
     208           3 : int fd_is_temporary_fs(int fd) {
     209             :         struct statfs s;
     210             : 
     211           3 :         if (fstatfs(fd, &s) < 0)
     212           0 :                 return -errno;
     213             : 
     214           3 :         return is_temporary_fs(&s);
     215             : }
     216             : 
     217       10155 : int fd_is_network_fs(int fd) {
     218             :         struct statfs s;
     219             : 
     220       10155 :         if (fstatfs(fd, &s) < 0)
     221           0 :                 return -errno;
     222             : 
     223       10155 :         return is_network_fs(&s);
     224             : }
     225             : 
     226           3 : int path_is_temporary_fs(const char *path) {
     227           3 :         _cleanup_close_ int fd = -1;
     228             : 
     229           3 :         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
     230           3 :         if (fd < 0)
     231           1 :                 return -errno;
     232             : 
     233           2 :         return fd_is_temporary_fs(fd);
     234             : }
     235             : 
     236       21169 : int stat_verify_regular(const struct stat *st) {
     237       21169 :         assert(st);
     238             : 
     239             :         /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
     240             :          * code. */
     241             : 
     242       21169 :         if (S_ISDIR(st->st_mode))
     243           0 :                 return -EISDIR;
     244             : 
     245       21169 :         if (S_ISLNK(st->st_mode))
     246           0 :                 return -ELOOP;
     247             : 
     248       21169 :         if (!S_ISREG(st->st_mode))
     249           0 :                 return -EBADFD;
     250             : 
     251       21169 :         return 0;
     252             : }
     253             : 
     254         720 : int fd_verify_regular(int fd) {
     255             :         struct stat st;
     256             : 
     257         720 :         assert(fd >= 0);
     258             : 
     259         720 :         if (fstat(fd, &st) < 0)
     260           0 :                 return -errno;
     261             : 
     262         720 :         return stat_verify_regular(&st);
     263             : }
     264             : 
     265           0 : int stat_verify_directory(const struct stat *st) {
     266           0 :         assert(st);
     267             : 
     268           0 :         if (S_ISLNK(st->st_mode))
     269           0 :                 return -ELOOP;
     270             : 
     271           0 :         if (!S_ISDIR(st->st_mode))
     272           0 :                 return -ENOTDIR;
     273             : 
     274           0 :         return 0;
     275             : }
     276             : 
     277           0 : int fd_verify_directory(int fd) {
     278             :         struct stat st;
     279             : 
     280           0 :         assert(fd >= 0);
     281             : 
     282           0 :         if (fstat(fd, &st) < 0)
     283           0 :                 return -errno;
     284             : 
     285           0 :         return stat_verify_directory(&st);
     286             : }
     287             : 
     288          12 : int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
     289             :         const char *t;
     290             : 
     291             :         /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
     292             : 
     293          12 :         if (S_ISCHR(mode))
     294          12 :                 t = "char";
     295           0 :         else if (S_ISBLK(mode))
     296           0 :                 t = "block";
     297             :         else
     298           0 :                 return -ENODEV;
     299             : 
     300          12 :         if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
     301           0 :                 return -ENOMEM;
     302             : 
     303          12 :         return 0;
     304             : }
     305             : 
     306           6 : int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
     307           6 :         _cleanup_free_ char *p = NULL;
     308             :         int r;
     309             : 
     310             :         /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
     311             : 
     312           6 :         assert(ret);
     313             : 
     314           6 :         if (major(devno) == 0 && minor(devno) == 0) {
     315             :                 char *s;
     316             : 
     317             :                 /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
     318             :                  * /dev/block/ and /dev/char/, hence we handle them specially here. */
     319             : 
     320           0 :                 if (S_ISCHR(mode))
     321           0 :                         s = strdup("/run/systemd/inaccessible/chr");
     322           0 :                 else if (S_ISBLK(mode))
     323           0 :                         s = strdup("/run/systemd/inaccessible/blk");
     324             :                 else
     325           0 :                         return -ENODEV;
     326             : 
     327           0 :                 if (!s)
     328           0 :                         return -ENOMEM;
     329             : 
     330           0 :                 *ret = s;
     331           0 :                 return 0;
     332             :         }
     333             : 
     334           6 :         r = device_path_make_major_minor(mode, devno, &p);
     335           6 :         if (r < 0)
     336           0 :                 return r;
     337             : 
     338           6 :         return chase_symlinks(p, NULL, 0, ret);
     339             : }
     340             : 
     341           6 : int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {
     342             :         mode_t mode;
     343             :         dev_t devno;
     344             :         int r;
     345             : 
     346             :         /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
     347             :          * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
     348             :          * path cannot be parsed like this.  */
     349             : 
     350           6 :         if (path_equal(path, "/run/systemd/inaccessible/chr")) {
     351           0 :                 mode = S_IFCHR;
     352           0 :                 devno = makedev(0, 0);
     353           6 :         } else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
     354           0 :                 mode = S_IFBLK;
     355           0 :                 devno = makedev(0, 0);
     356             :         } else {
     357             :                 const char *w;
     358             : 
     359           6 :                 w = path_startswith(path, "/dev/block/");
     360           6 :                 if (w)
     361           0 :                         mode = S_IFBLK;
     362             :                 else {
     363           6 :                         w = path_startswith(path, "/dev/char/");
     364           6 :                         if (!w)
     365           0 :                                 return -ENODEV;
     366             : 
     367           6 :                         mode = S_IFCHR;
     368             :                 }
     369             : 
     370           6 :                 r = parse_dev(w, &devno);
     371           6 :                 if (r < 0)
     372           0 :                         return r;
     373             :         }
     374             : 
     375           6 :         if (ret_mode)
     376           6 :                 *ret_mode = mode;
     377           6 :         if (ret_devno)
     378           6 :                 *ret_devno = devno;
     379             : 
     380           6 :         return 0;
     381             : }

Generated by: LCOV version 1.14