]>
Commit | Line | Data |
---|---|---|
f34c169a AK |
1 | /* |
2 | * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | |
147d5fac | 3 | * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. |
f34c169a AK |
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 | |
147d5fac | 9 | * of the GNU Lesser General Public License v.2.1. |
f34c169a | 10 | * |
147d5fac | 11 | * You should have received a copy of the GNU Lesser General Public License |
f34c169a AK |
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 | ||
3e5b6ed2 | 16 | #include "dmlib.h" |
f34c169a AK |
17 | |
18 | #include <sys/file.h> | |
19 | #include <fcntl.h> | |
20 | #include <dirent.h> | |
3d2aecf0 | 21 | |
f34c169a AK |
22 | static int _create_dir_recursive(const char *dir) |
23 | { | |
24 | char *orig, *s; | |
7dc850db | 25 | int rc, r = 0; |
f34c169a AK |
26 | |
27 | log_verbose("Creating directory \"%s\"", dir); | |
28 | /* Create parent directories */ | |
5e3bd867 | 29 | orig = s = dm_strdup(dir); |
b23975ee ZK |
30 | if (!s) { |
31 | log_error("Failed to duplicate directory name."); | |
32 | return 0; | |
33 | } | |
34 | ||
f34c169a AK |
35 | while ((s = strchr(s, '/')) != NULL) { |
36 | *s = '\0'; | |
37 | if (*orig) { | |
38 | rc = mkdir(orig, 0777); | |
39 | if (rc < 0 && errno != EEXIST) { | |
1c200869 JM |
40 | if (errno != EROFS) |
41 | log_sys_error("mkdir", orig); | |
7dc850db | 42 | goto out; |
f34c169a AK |
43 | } |
44 | } | |
45 | *s++ = '/'; | |
46 | } | |
f34c169a AK |
47 | |
48 | /* Create final directory */ | |
49 | rc = mkdir(dir, 0777); | |
50 | if (rc < 0 && errno != EEXIST) { | |
1c200869 JM |
51 | if (errno != EROFS) |
52 | log_sys_error("mkdir", orig); | |
7dc850db | 53 | goto out; |
f34c169a | 54 | } |
7dc850db AK |
55 | |
56 | r = 1; | |
57 | out: | |
58 | dm_free(orig); | |
59 | return r; | |
f34c169a AK |
60 | } |
61 | ||
3f311f1d | 62 | int dm_create_dir(const char *dir) |
f34c169a AK |
63 | { |
64 | struct stat info; | |
65 | ||
66 | if (!*dir) | |
67 | return 1; | |
68 | ||
69 | if (stat(dir, &info) < 0) | |
70 | return _create_dir_recursive(dir); | |
71 | ||
72 | if (S_ISDIR(info.st_mode)) | |
73 | return 1; | |
74 | ||
75 | log_error("Directory \"%s\" not found", dir); | |
76 | return 0; | |
77 | } | |
78 | ||
14254bd0 PR |
79 | int dm_is_empty_dir(const char *dir) |
80 | { | |
81 | struct dirent *dirent; | |
82 | DIR *d; | |
83 | ||
84 | if (!(d = opendir(dir))) { | |
85 | log_sys_error("opendir", dir); | |
86 | return 0; | |
87 | } | |
88 | ||
89 | while ((dirent = readdir(d))) | |
90 | if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, "..")) | |
91 | break; | |
92 | ||
93 | if (closedir(d)) | |
94 | log_sys_error("closedir", dir); | |
95 | ||
96 | return dirent ? 0 : 1; | |
97 | } | |
98 | ||
0c3cd7e2 JM |
99 | int dm_fclose(FILE *stream) |
100 | { | |
101 | int prev_fail = ferror(stream); | |
102 | int fclose_fail = fclose(stream); | |
103 | ||
104 | /* If there was a previous failure, but fclose succeeded, | |
105 | clear errno, since ferror does not set it, and its value | |
106 | may be unrelated to the ferror-reported failure. */ | |
107 | if (prev_fail && !fclose_fail) | |
108 | errno = 0; | |
109 | ||
110 | return prev_fail || fclose_fail ? EOF : 0; | |
111 | } | |
8c4e8a18 FDN |
112 | |
113 | int dm_create_lockfile(const char *lockfile) | |
114 | { | |
115 | int fd, value; | |
116 | size_t bufferlen; | |
117 | ssize_t write_out; | |
118 | struct flock lock; | |
119 | char buffer[50]; | |
d95a85ca | 120 | int retries = 0; |
8c4e8a18 FDN |
121 | |
122 | if((fd = open(lockfile, O_CREAT | O_WRONLY, | |
123 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { | |
124 | log_error("Cannot open lockfile [%s], error was [%s]", | |
125 | lockfile, strerror(errno)); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | lock.l_type = F_WRLCK; | |
130 | lock.l_start = 0; | |
131 | lock.l_whence = SEEK_SET; | |
132 | lock.l_len = 0; | |
4cc5adf4 | 133 | retry_fcntl: |
8c4e8a18 | 134 | if (fcntl(fd, F_SETLK, &lock) < 0) { |
4cc5adf4 AK |
135 | switch (errno) { |
136 | case EINTR: | |
137 | goto retry_fcntl; | |
4cc5adf4 AK |
138 | case EACCES: |
139 | case EAGAIN: | |
d95a85ca PR |
140 | if (retries == 20) { |
141 | log_error("Cannot lock lockfile [%s], error was [%s]", | |
142 | lockfile, strerror(errno)); | |
143 | break; | |
144 | } else { | |
145 | ++ retries; | |
146 | usleep(1000); | |
147 | goto retry_fcntl; | |
148 | } | |
4cc5adf4 | 149 | default: |
8c4e8a18 | 150 | log_error("process is already running"); |
4cc5adf4 | 151 | } |
8c4e8a18 | 152 | |
4cc5adf4 | 153 | goto fail_close; |
8c4e8a18 FDN |
154 | } |
155 | ||
156 | if (ftruncate(fd, 0) < 0) { | |
157 | log_error("Cannot truncate pidfile [%s], error was [%s]", | |
158 | lockfile, strerror(errno)); | |
159 | ||
4cc5adf4 | 160 | goto fail_close_unlink; |
8c4e8a18 FDN |
161 | } |
162 | ||
163 | memset(buffer, 0, sizeof(buffer)); | |
164 | snprintf(buffer, sizeof(buffer)-1, "%u\n", getpid()); | |
165 | ||
166 | bufferlen = strlen(buffer); | |
167 | write_out = write(fd, buffer, bufferlen); | |
168 | ||
169 | if ((write_out < 0) || (write_out == 0 && errno)) { | |
170 | log_error("Cannot write pid to pidfile [%s], error was [%s]", | |
171 | lockfile, strerror(errno)); | |
172 | ||
4cc5adf4 | 173 | goto fail_close_unlink; |
8c4e8a18 FDN |
174 | } |
175 | ||
a1eba521 | 176 | if ((write_out == 0) || ((size_t)write_out < bufferlen)) { |
8c4e8a18 FDN |
177 | log_error("Cannot write pid to pidfile [%s], shortwrite of" |
178 | "[%" PRIsize_t "] bytes, expected [%" PRIsize_t "]\n", | |
179 | lockfile, write_out, bufferlen); | |
180 | ||
4cc5adf4 | 181 | goto fail_close_unlink; |
8c4e8a18 FDN |
182 | } |
183 | ||
184 | if ((value = fcntl(fd, F_GETFD, 0)) < 0) { | |
185 | log_error("Cannot get close-on-exec flag from pidfile [%s], " | |
186 | "error was [%s]", lockfile, strerror(errno)); | |
187 | ||
4cc5adf4 | 188 | goto fail_close_unlink; |
8c4e8a18 FDN |
189 | } |
190 | value |= FD_CLOEXEC; | |
191 | if (fcntl(fd, F_SETFD, value) < 0) { | |
192 | log_error("Cannot set close-on-exec flag from pidfile [%s], " | |
193 | "error was [%s]", lockfile, strerror(errno)); | |
194 | ||
4cc5adf4 | 195 | goto fail_close_unlink; |
8c4e8a18 FDN |
196 | } |
197 | ||
198 | return 1; | |
199 | ||
4cc5adf4 | 200 | fail_close_unlink: |
8c4e8a18 FDN |
201 | if (unlink(lockfile)) |
202 | stack; | |
4cc5adf4 AK |
203 | fail_close: |
204 | if (close(fd)) | |
205 | stack; | |
8c4e8a18 FDN |
206 | |
207 | return 0; | |
208 | } | |
405c4a45 JEB |
209 | |
210 | int dm_daemon_is_running(const char* lockfile) | |
211 | { | |
212 | int fd; | |
213 | struct flock lock; | |
214 | ||
215 | if((fd = open(lockfile, O_RDONLY)) < 0) | |
216 | return 0; | |
217 | ||
218 | lock.l_type = F_WRLCK; | |
219 | lock.l_start = 0; | |
220 | lock.l_whence = SEEK_SET; | |
221 | lock.l_len = 0; | |
222 | if (fcntl(fd, F_GETLK, &lock) < 0) { | |
223 | log_error("Cannot check lock status of lockfile [%s], error was [%s]", | |
224 | lockfile, strerror(errno)); | |
225 | if (close(fd)) | |
226 | stack; | |
227 | return 0; | |
228 | } | |
229 | ||
230 | if (close(fd)) | |
231 | stack; | |
232 | ||
233 | return (lock.l_type == F_UNLCK) ? 0 : 1; | |
234 | } |