Coverage Report

Created: 2025-06-13 06:36

/src/lvm2/libdm/libdm-file.c
Line
Count
Source (jump to first uncovered line)
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 the device-mapper userspace tools.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14
 */
15
16
#include "libdm/misc/dmlib.h"
17
18
#include <sys/file.h>
19
#include <fcntl.h>
20
#include <dirent.h>
21
22
static int _is_dir(const char *path)
23
0
{
24
0
  struct stat st;
25
26
0
  if (stat(path, &st) < 0) {
27
0
    log_sys_error("stat", path);
28
0
    return 0;
29
0
  }
30
31
0
  if (!S_ISDIR(st.st_mode)) {
32
0
    log_error("Existing path %s is not "
33
0
        "a directory.", path);
34
0
    return 0;
35
0
  }
36
37
0
  return 1;
38
0
}
39
40
static int _create_dir_recursive(const char *dir)
41
0
{
42
0
  char *orig, *s;
43
0
  int rc, r = 0;
44
45
0
  log_verbose("Creating directory \"%s\"", dir);
46
  /* Create parent directories */
47
0
  orig = s = dm_strdup(dir);
48
0
  if (!s) {
49
0
    log_error("Failed to duplicate directory name.");
50
0
    return 0;
51
0
  }
52
53
0
  while ((s = strchr(s, '/')) != NULL) {
54
0
    *s = '\0';
55
0
    if (*orig) {
56
0
      rc = mkdir(orig, 0777);
57
0
      if (rc < 0) {
58
0
        if (errno == EEXIST) {
59
0
          if (!_is_dir(orig))
60
0
            goto_out;
61
0
        } else {
62
0
          if (errno != EROFS)
63
0
            log_sys_error("mkdir", orig);
64
0
          goto out;
65
0
        }
66
0
      }
67
0
    }
68
0
    *s++ = '/';
69
0
  }
70
71
  /* Create final directory */
72
0
  rc = mkdir(dir, 0777);
73
0
  if (rc < 0) {
74
0
    if (errno == EEXIST) {
75
0
      if (!_is_dir(dir))
76
0
        goto_out;
77
0
    } else {
78
0
      if (errno != EROFS)
79
0
        log_sys_error("mkdir", orig);
80
0
      goto out;
81
0
    }
82
0
  }
83
84
0
  r = 1;
85
0
out:
86
0
  dm_free(orig);
87
0
  return r;
88
0
}
89
90
int dm_create_dir(const char *dir)
91
0
{
92
0
  struct stat info;
93
94
0
  if (!*dir)
95
0
    return 1;
96
97
0
  if (stat(dir, &info) == 0 && S_ISDIR(info.st_mode))
98
0
    return 1;
99
100
0
  if (!_create_dir_recursive(dir))
101
0
    return_0;
102
103
0
  return 1;
104
0
}
105
106
int dm_is_empty_dir(const char *dir)
107
0
{
108
0
  struct dirent *dirent;
109
0
  DIR *d;
110
111
0
  if (!(d = opendir(dir))) {
112
0
    log_sys_error("opendir", dir);
113
0
    return 0;
114
0
  }
115
116
0
  while ((dirent = readdir(d)))
117
0
    if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
118
0
      break;
119
120
0
  if (closedir(d))
121
0
    log_sys_debug("closedir", dir);
122
123
0
  return dirent ? 0 : 1;
124
0
}
125
126
int dm_fclose(FILE *stream)
127
0
{
128
0
  int prev_fail = ferror(stream);
129
0
  int fclose_fail = fclose(stream);
130
131
  /* If there was a previous failure, but fclose succeeded,
132
     clear errno, since ferror does not set it, and its value
133
     may be unrelated to the ferror-reported failure.  */
134
0
  if (prev_fail && !fclose_fail)
135
0
    errno = 0;
136
137
0
  return prev_fail || fclose_fail ? EOF : 0;
138
0
}
139
140
int dm_create_lockfile(const char *lockfile)
141
0
{
142
0
  int fd, value;
143
0
  size_t bufferlen;
144
0
  ssize_t write_out;
145
0
  struct flock lock;
146
0
  char buffer[50];
147
0
  int retries = 0;
148
149
0
  if ((fd = open(lockfile, O_CREAT | O_WRONLY,
150
0
           (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
151
0
    log_error("Cannot open lockfile [%s], error was [%s]",
152
0
        lockfile, strerror(errno));
153
0
    return 0;
154
0
  }
155
156
0
  lock.l_type = F_WRLCK;
157
0
  lock.l_start = 0;
158
0
  lock.l_whence = SEEK_SET;
159
0
  lock.l_len = 0;
160
0
retry_fcntl:
161
0
  if (fcntl(fd, F_SETLK, &lock) < 0) {
162
0
    switch (errno) {
163
0
    case EINTR:
164
0
      goto retry_fcntl;
165
0
    case EACCES:
166
0
    case EAGAIN:
167
0
      if (retries == 20) {
168
0
        log_error("Cannot lock lockfile [%s], error was [%s]",
169
0
            lockfile, strerror(errno));
170
0
        break;
171
0
      } else {
172
0
        ++ retries;
173
0
        usleep(1000);
174
0
        goto retry_fcntl;
175
0
      }
176
0
    default:
177
0
      log_error("process is already running");
178
0
    }
179
180
0
    goto fail_close;
181
0
  }
182
183
0
  if (ftruncate(fd, 0) < 0) {
184
0
    log_error("Cannot truncate pidfile [%s], error was [%s]",
185
0
        lockfile, strerror(errno));
186
187
0
    goto fail_close_unlink;
188
0
  }
189
190
0
  snprintf(buffer, sizeof(buffer), "%u\n", getpid());
191
192
0
  bufferlen = strlen(buffer);
193
0
  write_out = write(fd, buffer, bufferlen);
194
195
0
  if ((write_out < 0) || (write_out == 0 && errno)) {
196
0
    log_error("Cannot write pid to pidfile [%s], error was [%s]",
197
0
        lockfile, strerror(errno));
198
199
0
    goto fail_close_unlink;
200
0
  }
201
202
0
  if ((write_out == 0) || ((size_t)write_out < bufferlen)) {
203
0
    log_error("Cannot write pid to pidfile [%s], shortwrite of"
204
0
        "[%" PRIsize_t "] bytes, expected [%" PRIsize_t "]\n",
205
0
        lockfile, write_out, bufferlen);
206
207
0
    goto fail_close_unlink;
208
0
  }
209
210
0
  if ((value = fcntl(fd, F_GETFD, 0)) < 0) {
211
0
    log_error("Cannot get close-on-exec flag from pidfile [%s], "
212
0
        "error was [%s]", lockfile, strerror(errno));
213
214
0
    goto fail_close_unlink;
215
0
  }
216
0
  value |= FD_CLOEXEC;
217
0
  if (fcntl(fd, F_SETFD, value) < 0) {
218
0
    log_error("Cannot set close-on-exec flag from pidfile [%s], "
219
0
        "error was [%s]", lockfile, strerror(errno));
220
221
0
    goto fail_close_unlink;
222
0
  }
223
224
  /* coverity[leaked_handle] intentional leak of fd handle here  */
225
0
  return 1;
226
227
0
fail_close_unlink:
228
0
  if (unlink(lockfile))
229
0
    log_sys_debug("unlink", lockfile);
230
0
fail_close:
231
0
  if (close(fd))
232
0
    log_sys_debug("close", lockfile);
233
234
0
  return 0;
235
0
}
236
237
int dm_daemon_is_running(const char* lockfile)
238
0
{
239
0
       int fd;
240
0
       struct flock lock;
241
242
0
       if((fd = open(lockfile, O_RDONLY)) < 0)
243
0
               return 0;
244
245
0
       lock.l_type = F_WRLCK;
246
0
       lock.l_start = 0;
247
0
       lock.l_whence = SEEK_SET;
248
0
       lock.l_len = 0;
249
0
       if (fcntl(fd, F_GETLK, &lock) < 0) {
250
0
               log_error("Cannot check lock status of lockfile [%s], error was [%s]",
251
0
                         lockfile, strerror(errno));
252
0
               if (close(fd))
253
0
                       stack;
254
0
               return 0;
255
0
       }
256
257
0
       if (close(fd))
258
0
               stack;
259
260
0
       return (lock.l_type == F_UNLCK) ? 0 : 1;
261
0
}