LCOV - code coverage report
Current view: top level - basic - stat-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 133 185 71.9 %
Date: 2019-08-23 13:36:53 Functions: 22 25 88.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 84 160 52.5 %

           Branch data     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                 :        112 : int is_symlink(const char *path) {
      24                 :            :         struct stat info;
      25                 :            : 
      26         [ -  + ]:        112 :         assert(path);
      27                 :            : 
      28         [ +  + ]:        112 :         if (lstat(path, &info) < 0)
      29                 :         92 :                 return -errno;
      30                 :            : 
      31                 :         20 :         return !!S_ISLNK(info.st_mode);
      32                 :            : }
      33                 :            : 
      34                 :       6628 : int is_dir(const char* path, bool follow) {
      35                 :            :         struct stat st;
      36                 :            :         int r;
      37                 :            : 
      38         [ -  + ]:       6628 :         assert(path);
      39                 :            : 
      40         [ +  + ]:       6628 :         if (follow)
      41                 :       1852 :                 r = stat(path, &st);
      42                 :            :         else
      43                 :       4776 :                 r = lstat(path, &st);
      44         [ +  + ]:       6628 :         if (r < 0)
      45                 :        224 :                 return -errno;
      46                 :            : 
      47                 :       6404 :         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                 :          4 : int is_device_node(const char *path) {
      60                 :            :         struct stat info;
      61                 :            : 
      62         [ -  + ]:          4 :         assert(path);
      63                 :            : 
      64         [ +  - ]:          4 :         if (lstat(path, &info) < 0)
      65                 :          4 :                 return -errno;
      66                 :            : 
      67   [ #  #  #  # ]:          0 :         return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
      68                 :            : }
      69                 :            : 
      70                 :         80 : int dir_is_empty_at(int dir_fd, const char *path) {
      71                 :         80 :         _cleanup_close_ int fd = -1;
      72                 :         80 :         _cleanup_closedir_ DIR *d = NULL;
      73                 :            :         struct dirent *de;
      74                 :            : 
      75         [ +  - ]:         80 :         if (path)
      76                 :         80 :                 fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
      77                 :            :         else
      78                 :          0 :                 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
      79         [ +  + ]:         80 :         if (fd < 0)
      80                 :          8 :                 return -errno;
      81                 :            : 
      82                 :         72 :         d = fdopendir(fd);
      83         [ -  + ]:         72 :         if (!d)
      84                 :          0 :                 return -errno;
      85                 :         72 :         fd = -1;
      86                 :            : 
      87   [ +  +  -  +  :        104 :         FOREACH_DIRENT(de, d, return -errno)
                   +  + ]
      88                 :         64 :                 return 0;
      89                 :            : 
      90                 :          8 :         return 1;
      91                 :            : }
      92                 :            : 
      93                 :       7308 : bool null_or_empty(struct stat *st) {
      94         [ -  + ]:       7308 :         assert(st);
      95                 :            : 
      96   [ +  +  +  + ]:       7308 :         if (S_ISREG(st->st_mode) && st->st_size <= 0)
      97                 :         24 :                 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   [ +  +  -  + ]:       7284 :         if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
     103                 :         36 :                 return true;
     104                 :            : 
     105                 :       7248 :         return false;
     106                 :            : }
     107                 :            : 
     108                 :       3388 : int null_or_empty_path(const char *fn) {
     109                 :            :         struct stat st;
     110                 :            : 
     111         [ -  + ]:       3388 :         assert(fn);
     112                 :            : 
     113         [ -  + ]:       3388 :         if (stat(fn, &st) < 0)
     114                 :          0 :                 return -errno;
     115                 :            : 
     116                 :       3388 :         return null_or_empty(&st);
     117                 :            : }
     118                 :            : 
     119                 :         12 : int null_or_empty_fd(int fd) {
     120                 :            :         struct stat st;
     121                 :            : 
     122         [ -  + ]:         12 :         assert(fd >= 0);
     123                 :            : 
     124         [ -  + ]:         12 :         if (fstat(fd, &st) < 0)
     125                 :          0 :                 return -errno;
     126                 :            : 
     127                 :         12 :         return null_or_empty(&st);
     128                 :            : }
     129                 :            : 
     130                 :         32 : int path_is_read_only_fs(const char *path) {
     131                 :            :         struct statvfs st;
     132                 :            : 
     133         [ -  + ]:         32 :         assert(path);
     134                 :            : 
     135         [ -  + ]:         32 :         if (statvfs(path, &st) < 0)
     136                 :          0 :                 return -errno;
     137                 :            : 
     138         [ -  + ]:         32 :         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   [ +  +  -  + ]:         32 :         if (access(path, W_OK) < 0 && errno == EROFS)
     145                 :          0 :                 return true;
     146                 :            : 
     147                 :         32 :         return false;
     148                 :            : }
     149                 :            : 
     150                 :        724 : int files_same(const char *filea, const char *fileb, int flags) {
     151                 :            :         struct stat a, b;
     152                 :            : 
     153         [ -  + ]:        724 :         assert(filea);
     154         [ -  + ]:        724 :         assert(fileb);
     155                 :            : 
     156         [ +  + ]:        724 :         if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
     157                 :        360 :                 return -errno;
     158                 :            : 
     159         [ +  + ]:        364 :         if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
     160                 :         16 :                 return -errno;
     161                 :            : 
     162         [ +  + ]:        472 :         return a.st_dev == b.st_dev &&
     163         [ +  + ]:        124 :                a.st_ino == b.st_ino;
     164                 :            : }
     165                 :            : 
     166                 :     325252 : bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
     167         [ -  + ]:     325252 :         assert(s);
     168                 :            :         assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
     169                 :            : 
     170                 :     325252 :         return F_TYPE_EQUAL(s->f_type, magic_value);
     171                 :            : }
     172                 :            : 
     173                 :        232 : int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
     174                 :            :         struct statfs s;
     175                 :            : 
     176         [ -  + ]:        232 :         if (fstatfs(fd, &s) < 0)
     177                 :          0 :                 return -errno;
     178                 :            : 
     179                 :        232 :         return is_fs_type(&s, magic_value);
     180                 :            : }
     181                 :            : 
     182                 :         20 : int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
     183                 :         20 :         _cleanup_close_ int fd = -1;
     184                 :            : 
     185                 :         20 :         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
     186         [ +  + ]:         20 :         if (fd < 0)
     187                 :          4 :                 return -errno;
     188                 :            : 
     189                 :         16 :         return fd_is_fs_type(fd, magic_value);
     190                 :            : }
     191                 :            : 
     192                 :         16 : bool is_temporary_fs(const struct statfs *s) {
     193         [ +  + ]:         20 :         return is_fs_type(s, TMPFS_MAGIC) ||
     194         [ -  + ]:          4 :                 is_fs_type(s, RAMFS_MAGIC);
     195                 :            : }
     196                 :            : 
     197                 :      40620 : bool is_network_fs(const struct statfs *s) {
     198                 :      81240 :         return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
     199         [ +  - ]:      40620 :                 is_fs_type(s, CODA_SUPER_MAGIC) ||
     200         [ +  - ]:      40620 :                 is_fs_type(s, NCP_SUPER_MAGIC) ||
     201         [ +  - ]:      40620 :                 is_fs_type(s, NFS_SUPER_MAGIC) ||
     202         [ +  - ]:      40620 :                 is_fs_type(s, SMB_SUPER_MAGIC) ||
     203         [ +  - ]:      40620 :                 is_fs_type(s, V9FS_MAGIC) ||
     204   [ +  -  +  - ]:     121860 :                 is_fs_type(s, AFS_SUPER_MAGIC) ||
     205         [ -  + ]:      40620 :                 is_fs_type(s, OCFS2_SUPER_MAGIC);
     206                 :            : }
     207                 :            : 
     208                 :         12 : int fd_is_temporary_fs(int fd) {
     209                 :            :         struct statfs s;
     210                 :            : 
     211         [ -  + ]:         12 :         if (fstatfs(fd, &s) < 0)
     212                 :          0 :                 return -errno;
     213                 :            : 
     214                 :         12 :         return is_temporary_fs(&s);
     215                 :            : }
     216                 :            : 
     217                 :      40620 : int fd_is_network_fs(int fd) {
     218                 :            :         struct statfs s;
     219                 :            : 
     220         [ -  + ]:      40620 :         if (fstatfs(fd, &s) < 0)
     221                 :          0 :                 return -errno;
     222                 :            : 
     223                 :      40620 :         return is_network_fs(&s);
     224                 :            : }
     225                 :            : 
     226                 :         12 : int path_is_temporary_fs(const char *path) {
     227                 :         12 :         _cleanup_close_ int fd = -1;
     228                 :            : 
     229                 :         12 :         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
     230         [ +  + ]:         12 :         if (fd < 0)
     231                 :          4 :                 return -errno;
     232                 :            : 
     233                 :          8 :         return fd_is_temporary_fs(fd);
     234                 :            : }
     235                 :            : 
     236                 :      84810 : int stat_verify_regular(const struct stat *st) {
     237         [ -  + ]:      84810 :         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         [ -  + ]:      84810 :         if (S_ISDIR(st->st_mode))
     243                 :          0 :                 return -EISDIR;
     244                 :            : 
     245         [ -  + ]:      84810 :         if (S_ISLNK(st->st_mode))
     246                 :          0 :                 return -ELOOP;
     247                 :            : 
     248         [ -  + ]:      84810 :         if (!S_ISREG(st->st_mode))
     249                 :          0 :                 return -EBADFD;
     250                 :            : 
     251                 :      84810 :         return 0;
     252                 :            : }
     253                 :            : 
     254                 :       3014 : int fd_verify_regular(int fd) {
     255                 :            :         struct stat st;
     256                 :            : 
     257         [ -  + ]:       3014 :         assert(fd >= 0);
     258                 :            : 
     259         [ -  + ]:       3014 :         if (fstat(fd, &st) < 0)
     260                 :          0 :                 return -errno;
     261                 :            : 
     262                 :       3014 :         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                 :         48 : 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         [ +  - ]:         48 :         if (S_ISCHR(mode))
     294                 :         48 :                 t = "char";
     295         [ #  # ]:          0 :         else if (S_ISBLK(mode))
     296                 :          0 :                 t = "block";
     297                 :            :         else
     298                 :          0 :                 return -ENODEV;
     299                 :            : 
     300         [ -  + ]:         48 :         if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
     301                 :          0 :                 return -ENOMEM;
     302                 :            : 
     303                 :         48 :         return 0;
     304                 :            : }
     305                 :            : 
     306                 :         24 : int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
     307                 :         24 :         _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         [ -  + ]:         24 :         assert(ret);
     313                 :            : 
     314   [ -  +  #  # ]:         24 :         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                 :         24 :         r = device_path_make_major_minor(mode, devno, &p);
     335         [ -  + ]:         24 :         if (r < 0)
     336                 :          0 :                 return r;
     337                 :            : 
     338                 :         24 :         return chase_symlinks(p, NULL, 0, ret);
     339                 :            : }
     340                 :            : 
     341                 :         24 : 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         [ -  + ]:         24 :         if (path_equal(path, "/run/systemd/inaccessible/chr")) {
     351                 :          0 :                 mode = S_IFCHR;
     352                 :          0 :                 devno = makedev(0, 0);
     353         [ -  + ]:         24 :         } 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                 :         24 :                 w = path_startswith(path, "/dev/block/");
     360         [ -  + ]:         24 :                 if (w)
     361                 :          0 :                         mode = S_IFBLK;
     362                 :            :                 else {
     363                 :         24 :                         w = path_startswith(path, "/dev/char/");
     364         [ -  + ]:         24 :                         if (!w)
     365                 :          0 :                                 return -ENODEV;
     366                 :            : 
     367                 :         24 :                         mode = S_IFCHR;
     368                 :            :                 }
     369                 :            : 
     370                 :         24 :                 r = parse_dev(w, &devno);
     371         [ -  + ]:         24 :                 if (r < 0)
     372                 :          0 :                         return r;
     373                 :            :         }
     374                 :            : 
     375         [ +  - ]:         24 :         if (ret_mode)
     376                 :         24 :                 *ret_mode = mode;
     377         [ +  - ]:         24 :         if (ret_devno)
     378                 :         24 :                 *ret_devno = devno;
     379                 :            : 
     380                 :         24 :         return 0;
     381                 :            : }

Generated by: LCOV version 1.14