LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/lib/misc - lvm-file.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 5 113 4.4 %
Date: 2010-04-13 Functions: 1 9 11.1 %
Branches: 3 86 3.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
       4                 :            :  *
       5                 :            :  * This file is part of LVM2.
       6                 :            :  *
       7                 :            :  * This copyrighted material is made available to anyone wishing to use,
       8                 :            :  * modify, copy, or redistribute it subject to the terms and conditions
       9                 :            :  * of the GNU Lesser General Public License v.2.1.
      10                 :            :  *
      11                 :            :  * You should have received a copy of the GNU Lesser General Public License
      12                 :            :  * along with this program; if not, write to the Free Software Foundation,
      13                 :            :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "lib.h"
      17                 :            : #include "lvm-file.h"
      18                 :            : #include "lvm-string.h"
      19                 :            : 
      20                 :            : #include <unistd.h>
      21                 :            : #include <sys/stat.h>
      22                 :            : #include <sys/file.h>
      23                 :            : #include <fcntl.h>
      24                 :            : #include <dirent.h>
      25                 :            : 
      26                 :            : /*
      27                 :            :  * Creates a temporary filename, and opens a descriptor to the
      28                 :            :  * file.  Both the filename and descriptor are needed so we can
      29                 :            :  * rename the file after successfully writing it.  Grab
      30                 :            :  * NFS-supported exclusive fcntl discretionary lock.
      31                 :            :  */
      32                 :          0 : int create_temp_name(const char *dir, char *buffer, size_t len, int *fd,
      33                 :            :                      unsigned *seed)
      34                 :            : {
      35                 :            :         int i, num;
      36                 :            :         pid_t pid;
      37                 :            :         char hostname[255];
      38                 :            :         struct flock lock = {
      39                 :            :                 .l_type = F_WRLCK,
      40                 :            :                 .l_whence = 0,
      41                 :            :                 .l_start = 0,
      42                 :            :                 .l_len = 0
      43                 :          0 :         };
      44                 :            : 
      45                 :          0 :         num = rand_r(seed);
      46                 :          0 :         pid = getpid();
      47         [ #  # ]:          0 :         if (gethostname(hostname, sizeof(hostname)) < 0) {
      48                 :          0 :                 log_sys_error("gethostname", "");
      49                 :          0 :                 strcpy(hostname, "nohostname");
      50                 :            :         }
      51                 :            : 
      52         [ #  # ]:          0 :         for (i = 0; i < 20; i++, num++) {
      53                 :            : 
      54         [ #  # ]:          0 :                 if (dm_snprintf(buffer, len, "%s/.lvm_%s_%d_%d",
      55                 :            :                                  dir, hostname, pid, num) == -1) {
      56                 :          0 :                         log_error("Not enough space to build temporary file "
      57                 :            :                                   "string.");
      58                 :          0 :                         return 0;
      59                 :            :                 }
      60                 :            : 
      61                 :          0 :                 *fd = open(buffer, O_CREAT | O_EXCL | O_WRONLY | O_APPEND,
      62                 :            :                            S_IRUSR | S_IRGRP | S_IROTH |
      63                 :            :                            S_IWUSR | S_IWGRP | S_IWOTH);
      64         [ #  # ]:          0 :                 if (*fd < 0)
      65                 :          0 :                         continue;
      66                 :            : 
      67         [ #  # ]:          0 :                 if (!fcntl(*fd, F_SETLK, &lock))
      68                 :          0 :                         return 1;
      69                 :            : 
      70         [ #  # ]:          0 :                 if (close(*fd))
      71                 :          0 :                         log_sys_error("close", buffer);
      72                 :            :         }
      73                 :            : 
      74                 :          0 :         return 0;
      75                 :            : }
      76                 :            : 
      77                 :            : /*
      78                 :            :  * NFS-safe rename of a temporary file to a common name, designed
      79                 :            :  * to avoid race conditions and not overwrite the destination if
      80                 :            :  * it exists.
      81                 :            :  *
      82                 :            :  * Try to create the new filename as a hard link to the original.
      83                 :            :  * Check the link count of the original file to see if it worked.
      84                 :            :  * (Assumes nothing else touches our temporary file!)  If it
      85                 :            :  * worked, unlink the old filename.
      86                 :            :  */
      87                 :          0 : int lvm_rename(const char *old, const char *new)
      88                 :            : {
      89                 :            :         struct stat buf;
      90                 :            : 
      91         [ #  # ]:          0 :         if (link(old, new)) {
      92                 :          0 :                 log_error("%s: rename to %s failed: %s", old, new,
      93                 :            :                           strerror(errno));
      94                 :          0 :                 return 0;
      95                 :            :         }
      96                 :            : 
      97         [ #  # ]:          0 :         if (stat(old, &buf)) {
      98                 :          0 :                 log_sys_error("stat", old);
      99                 :          0 :                 return 0;
     100                 :            :         }
     101                 :            : 
     102         [ #  # ]:          0 :         if (buf.st_nlink != 2) {
     103                 :          0 :                 log_error("%s: rename to %s failed", old, new);
     104                 :          0 :                 return 0;
     105                 :            :         }
     106                 :            : 
     107         [ #  # ]:          0 :         if (unlink(old)) {
     108                 :          0 :                 log_sys_error("unlink", old);
     109                 :          0 :                 return 0;
     110                 :            :         }
     111                 :            : 
     112                 :          0 :         return 1;
     113                 :            : }
     114                 :            : 
     115                 :          0 : int path_exists(const char *path)
     116                 :            : {
     117                 :            :         struct stat info;
     118                 :            : 
     119         [ #  # ]:          0 :         if (!*path)
     120                 :          0 :                 return 0;
     121                 :            : 
     122         [ #  # ]:          0 :         if (stat(path, &info) < 0)
     123                 :          0 :                 return 0;
     124                 :            : 
     125                 :          0 :         return 1;
     126                 :            : }
     127                 :            : 
     128                 :          3 : int dir_exists(const char *path)
     129                 :            : {
     130                 :            :         struct stat info;
     131                 :            : 
     132         [ -  + ]:          3 :         if (!*path)
     133                 :          0 :                 return 0;
     134                 :            : 
     135         [ -  + ]:          3 :         if (stat(path, &info) < 0)
     136                 :          0 :                 return 0;
     137                 :            : 
     138         [ -  + ]:          3 :         if (!S_ISDIR(info.st_mode))
     139                 :          0 :                 return 0;
     140                 :            : 
     141                 :          3 :         return 1;
     142                 :            : }
     143                 :            : 
     144                 :          0 : int is_empty_dir(const char *dir)
     145                 :            : {
     146                 :            :         struct dirent *dirent;
     147                 :            :         DIR *d;
     148                 :            : 
     149         [ #  # ]:          0 :         if (!(d = opendir(dir))) {
     150                 :          0 :                 log_sys_error("opendir", dir);
     151                 :          0 :                 return 0;
     152                 :            :         }
     153                 :            : 
     154         [ #  # ]:          0 :         while ((dirent = readdir(d)))
     155 [ #  # ][ #  # ]:          0 :                 if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
     156                 :          0 :                         break;
     157                 :            : 
     158         [ #  # ]:          0 :         if (closedir(d)) {
     159                 :          0 :                 log_sys_error("closedir", dir);
     160                 :            :         }
     161                 :            : 
     162                 :          0 :         return dirent ? 0 : 1;
     163                 :            : }
     164                 :            : 
     165                 :          0 : void sync_dir(const char *file)
     166                 :            : {
     167                 :            :         int fd;
     168                 :            :         char *dir, *c;
     169                 :            : 
     170         [ #  # ]:          0 :         if (!(dir = dm_strdup(file))) {
     171                 :          0 :                 log_error("sync_dir failed in strdup");
     172                 :          0 :                 return;
     173                 :            :         }
     174                 :            : 
     175         [ #  # ]:          0 :         if (!dir_exists(dir)) {
     176                 :          0 :                 c = dir + strlen(dir);
     177 [ #  # ][ #  # ]:          0 :                 while (*c != '/' && c > dir)
     178                 :          0 :                         c--;
     179                 :            : 
     180         [ #  # ]:          0 :                 if (c == dir)
     181                 :          0 :                         *c++ = '.';
     182                 :            : 
     183                 :          0 :                 *c = '\0';
     184                 :            :         }
     185                 :            : 
     186         [ #  # ]:          0 :         if ((fd = open(dir, O_RDONLY)) == -1) {
     187                 :          0 :                 log_sys_error("open", dir);
     188                 :          0 :                 goto out;
     189                 :            :         }
     190                 :            : 
     191 [ #  # ][ #  # ]:          0 :         if (fsync(fd) && (errno != EROFS) && (errno != EINVAL))
                 [ #  # ]
     192                 :          0 :                 log_sys_error("fsync", dir);
     193                 :            : 
     194         [ #  # ]:          0 :         if (close(fd))
     195                 :          0 :                 log_sys_error("close", dir);
     196                 :            : 
     197                 :            :       out:
     198                 :          0 :         dm_free(dir);
     199                 :            : }
     200                 :            : 
     201                 :            : /*
     202                 :            :  * Attempt to obtain fcntl lock on a file, if necessary creating file first
     203                 :            :  * or waiting.
     204                 :            :  * Returns file descriptor on success, else -1.
     205                 :            :  * mode is F_WRLCK or F_RDLCK
     206                 :            :  */
     207                 :          0 : int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
     208                 :            : {
     209                 :            :         int lockfd;
     210                 :            :         char *dir;
     211                 :            :         char *c;
     212                 :            :         struct flock lock = {
     213                 :            :                 .l_type = lock_type,
     214                 :            :                 .l_whence = 0,
     215                 :            :                 .l_start = 0,
     216                 :            :                 .l_len = 0
     217                 :          0 :         };
     218                 :            : 
     219         [ #  # ]:          0 :         if (!(dir = dm_strdup(file))) {
     220                 :          0 :                 log_error("fcntl_lock_file failed in strdup.");
     221                 :          0 :                 return -1;
     222                 :            :         }
     223                 :            : 
     224         [ #  # ]:          0 :         if ((c = strrchr(dir, '/')))
     225                 :          0 :                 *c = '\0';
     226                 :            : 
     227         [ #  # ]:          0 :         if (!dm_create_dir(dir)) {
     228                 :          0 :                 dm_free(dir);
     229                 :          0 :                 return -1;
     230                 :            :         }
     231                 :            : 
     232                 :          0 :         dm_free(dir);
     233                 :            : 
     234         [ #  # ]:          0 :         log_very_verbose("Locking %s (%s, %hd)", file,
     235                 :            :                          (lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
     236                 :            :                          lock_type);
     237         [ #  # ]:          0 :         if ((lockfd = open(file, O_RDWR | O_CREAT, 0777)) < 0) {
     238                 :            :                 /* EACCES has been reported on NFS */
     239 [ #  # ][ #  # ]:          0 :                 if (warn_if_read_only || (errno != EROFS && errno != EACCES))
                 [ #  # ]
     240                 :          0 :                         log_sys_error("open", file);
     241                 :            :                 else
     242                 :          0 :                         stack;
     243                 :            : 
     244                 :          0 :                 return -1;
     245                 :            :         }
     246                 :            : 
     247         [ #  # ]:          0 :         if (fcntl(lockfd, F_SETLKW, &lock)) {
     248                 :          0 :                 log_sys_error("fcntl", file);
     249                 :          0 :                 close(lockfd);
     250                 :          0 :                 return -1;
     251                 :            :         }
     252                 :            : 
     253                 :          0 :         return lockfd;
     254                 :            : }
     255                 :            : 
     256                 :          0 : void fcntl_unlock_file(int lockfd)
     257                 :            : {
     258                 :            :         struct flock lock = {
     259                 :            :                 .l_type = F_UNLCK,
     260                 :            :                 .l_whence = 0,
     261                 :            :                 .l_start = 0,
     262                 :            :                 .l_len = 0
     263                 :          0 :         };
     264                 :            : 
     265                 :          0 :         log_very_verbose("Unlocking fd %d", lockfd);
     266                 :            : 
     267         [ #  # ]:          0 :         if (fcntl(lockfd, F_SETLK, &lock) == -1)
     268                 :          0 :                 log_error("fcntl unlock failed on fd %d: %s", lockfd,
     269                 :            :                           strerror(errno));
     270                 :            : 
     271         [ #  # ]:          0 :         if (close(lockfd))
     272                 :          0 :                 log_error("lock file close failed on fd %d: %s", lockfd,
     273                 :            :                           strerror(errno));
     274                 :          0 : }
     275                 :            : 
     276                 :          0 : int lvm_fclose(FILE *fp, const char *filename)
     277                 :            : {
     278         [ #  # ]:          0 :         if (!dm_fclose(fp))
     279                 :          0 :                 return 0;
     280         [ #  # ]:          0 :         if (errno == 0)
     281                 :          0 :                 log_error("%s: write error", filename);
     282                 :            :         else
     283                 :          0 :                 log_sys_error("write error", filename);
     284                 :          0 :         return EOF;
     285                 :            : }

Generated by: LCOV version 1.8