4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "lvm-string.h"
29 * Creates a temporary filename, and opens a descriptor to the
30 * file. Both the filename and descriptor are needed so we can
31 * rename the file after successfully writing it. Grab
32 * NFS-supported exclusive fcntl discretionary lock.
34 int create_temp_name(const char *dir
, char *buffer
, size_t len
, int *fd
,
49 if (gethostname(hostname
, sizeof(hostname
)) < 0) {
50 log_sys_error("gethostname", "");
51 strcpy(hostname
, "nohostname");
54 for (i
= 0; i
< 20; i
++, num
++) {
56 if (dm_snprintf(buffer
, len
, "%s/.lvm_%s_%d_%d",
57 dir
, hostname
, pid
, num
) == -1) {
58 log_error("Not enough space to build temporary file "
63 *fd
= open(buffer
, O_CREAT
| O_EXCL
| O_WRONLY
| O_APPEND
,
64 S_IRUSR
| S_IRGRP
| S_IROTH
|
65 S_IWUSR
| S_IWGRP
| S_IWOTH
);
69 if (!fcntl(*fd
, F_SETLK
, &lock
))
73 log_sys_error("close", buffer
);
80 * NFS-safe rename of a temporary file to a common name, designed
81 * to avoid race conditions and not overwrite the destination if
84 * Try to create the new filename as a hard link to the original.
85 * Check the link count of the original file to see if it worked.
86 * (Assumes nothing else touches our temporary file!) If it
87 * worked, unlink the old filename.
89 int lvm_rename(const char *old
, const char *new)
94 log_error("%s: rename to %s failed: %s", old
, new,
99 if (stat(old
, &buf
)) {
100 log_sys_error("stat", old
);
104 if (buf
.st_nlink
!= 2) {
105 log_error("%s: rename to %s failed", old
, new);
110 log_sys_error("unlink", old
);
117 int path_exists(const char *path
)
124 if (stat(path
, &info
) < 0)
130 int dir_exists(const char *path
)
137 if (stat(path
, &info
) < 0)
140 if (!S_ISDIR(info
.st_mode
))
146 int is_empty_dir(const char *dir
)
148 struct dirent
*dirent
;
151 if (!(d
= opendir(dir
))) {
152 log_sys_error("opendir", dir
);
156 while ((dirent
= readdir(d
)))
157 if (strcmp(dirent
->d_name
, ".") && strcmp(dirent
->d_name
, ".."))
161 log_sys_error("closedir", dir
);
164 return dirent
? 0 : 1;
167 void sync_dir(const char *file
)
172 if (!(dir
= dm_strdup(file
))) {
173 log_error("sync_dir failed in strdup");
177 if (!dir_exists(dir
)) {
178 c
= dir
+ strlen(dir
);
179 while (*c
!= '/' && c
> dir
)
188 if ((fd
= open(dir
, O_RDONLY
)) == -1) {
189 log_sys_error("open", dir
);
193 if (fsync(fd
) && (errno
!= EROFS
) && (errno
!= EINVAL
))
194 log_sys_error("fsync", dir
);
197 log_sys_error("close", dir
);
204 * Attempt to obtain fcntl lock on a file, if necessary creating file first
206 * Returns file descriptor on success, else -1.
207 * mode is F_WRLCK or F_RDLCK
209 int fcntl_lock_file(const char *file
, short lock_type
, int warn_if_read_only
)
214 struct flock lock
= {
221 if (!(dir
= dm_strdup(file
))) {
222 log_error("fcntl_lock_file failed in strdup.");
226 if ((c
= strrchr(dir
, '/')))
229 if (!dm_create_dir(dir
)) {
236 log_very_verbose("Locking %s (%s, %hd)", file
,
237 (lock_type
== F_WRLCK
) ? "F_WRLCK" : "F_RDLCK",
239 if ((lockfd
= open(file
, O_RDWR
| O_CREAT
, 0777)) < 0) {
240 /* EACCES has been reported on NFS */
241 if (warn_if_read_only
|| (errno
!= EROFS
&& errno
!= EACCES
))
242 log_sys_error("open", file
);
249 if (fcntl(lockfd
, F_SETLKW
, &lock
)) {
250 log_sys_error("fcntl", file
);
258 void fcntl_unlock_file(int lockfd
)
260 struct flock lock
= {
267 log_very_verbose("Unlocking fd %d", lockfd
);
269 if (fcntl(lockfd
, F_SETLK
, &lock
) == -1)
270 log_error("fcntl unlock failed on fd %d: %s", lockfd
,
274 log_error("lock file close failed on fd %d: %s", lockfd
,
278 int lvm_fclose(FILE *fp
, const char *filename
)
283 log_error("%s: write error", filename
);
285 log_sys_error("write error", filename
);