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 "fs.h"
18 : : #include "toolcontext.h"
19 : : #include "lvm-string.h"
20 : : #include "lvm-file.h"
21 : : #include "memlock.h"
22 : :
23 : : #include <sys/stat.h>
24 : : #include <fcntl.h>
25 : : #include <unistd.h>
26 : : #include <limits.h>
27 : : #include <dirent.h>
28 : :
29 : 0 : static int _mk_dir(const char *dev_dir, const char *vg_name)
30 : : {
31 : : char vg_path[PATH_MAX];
32 : : mode_t old_umask;
33 : :
34 [ # # ]: 0 : if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
35 : : dev_dir, vg_name) == -1) {
36 : 0 : log_error("Couldn't construct name of volume "
37 : : "group directory.");
38 : 0 : return 0;
39 : : }
40 : :
41 [ # # ]: 0 : if (dir_exists(vg_path))
42 : 0 : return 1;
43 : :
44 : 0 : log_very_verbose("Creating directory %s", vg_path);
45 : :
46 : 0 : old_umask = umask(DM_DEV_DIR_UMASK);
47 [ # # ]: 0 : if (mkdir(vg_path, 0777)) {
48 : 0 : log_sys_error("mkdir", vg_path);
49 : 0 : umask(old_umask);
50 : 0 : return 0;
51 : : }
52 : 0 : umask(old_umask);
53 : :
54 : 0 : return 1;
55 : : }
56 : :
57 : 0 : static int _rm_dir(const char *dev_dir, const char *vg_name)
58 : : {
59 : : char vg_path[PATH_MAX];
60 : :
61 [ # # ]: 0 : if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
62 : : dev_dir, vg_name) == -1) {
63 : 0 : log_error("Couldn't construct name of volume "
64 : : "group directory.");
65 : 0 : return 0;
66 : : }
67 : :
68 [ # # ][ # # ]: 0 : if (dir_exists(vg_path) && is_empty_dir(vg_path)) {
69 : 0 : log_very_verbose("Removing directory %s", vg_path);
70 : 0 : rmdir(vg_path);
71 : : }
72 : :
73 : 0 : return 1;
74 : : }
75 : :
76 : 0 : static void _rm_blks(const char *dir)
77 : : {
78 : : const char *name;
79 : : char path[PATH_MAX];
80 : : struct dirent *dirent;
81 : : struct stat buf;
82 : : DIR *d;
83 : :
84 [ # # ]: 0 : if (!(d = opendir(dir))) {
85 : 0 : log_sys_error("opendir", dir);
86 : 0 : return;
87 : : }
88 : :
89 [ # # ]: 0 : while ((dirent = readdir(d))) {
90 : 0 : name = dirent->d_name;
91 : :
92 [ # # ][ # # ]: 0 : if (!strcmp(name, ".") || !strcmp(name, ".."))
93 : 0 : continue;
94 : :
95 [ # # ]: 0 : if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
96 : 0 : log_error("Couldn't create path for %s", name);
97 : 0 : continue;
98 : : }
99 : :
100 [ # # ]: 0 : if (!lstat(path, &buf)) {
101 [ # # ]: 0 : if (!S_ISBLK(buf.st_mode))
102 : 0 : continue;
103 : 0 : log_very_verbose("Removing %s", path);
104 [ # # ]: 0 : if (unlink(path) < 0)
105 : 0 : log_sys_error("unlink", path);
106 : : }
107 : : }
108 : : }
109 : :
110 : 0 : static int _mk_link(const char *dev_dir, const char *vg_name,
111 : : const char *lv_name, const char *dev, int check_udev)
112 : : {
113 : : char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
114 : : char vg_path[PATH_MAX];
115 : : struct stat buf, buf_lp;
116 : :
117 [ # # ]: 0 : if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
118 : : dev_dir, vg_name) == -1) {
119 : 0 : log_error("Couldn't create path for volume group dir %s",
120 : : vg_name);
121 : 0 : return 0;
122 : : }
123 : :
124 [ # # ]: 0 : if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
125 : : lv_name) == -1) {
126 : 0 : log_error("Couldn't create source pathname for "
127 : : "logical volume link %s", lv_name);
128 : 0 : return 0;
129 : : }
130 : :
131 [ # # ]: 0 : if (dm_snprintf(link_path, sizeof(link_path), "%s/%s",
132 : : dm_dir(), dev) == -1) {
133 : 0 : log_error("Couldn't create destination pathname for "
134 : : "logical volume link for %s", lv_name);
135 : 0 : return 0;
136 : : }
137 : :
138 [ # # ]: 0 : if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
139 : : vg_path) == -1) {
140 : 0 : log_error("Couldn't create pathname for LVM1 group file for %s",
141 : : vg_name);
142 : 0 : return 0;
143 : : }
144 : :
145 : : /* To reach this point, the VG must have been locked.
146 : : * As locking fails if the VG is active under LVM1, it's
147 : : * now safe to remove any LVM1 devices we find here
148 : : * (as well as any existing LVM2 symlink). */
149 [ # # ]: 0 : if (!lstat(lvm1_group_path, &buf)) {
150 [ # # ]: 0 : if (!S_ISCHR(buf.st_mode)) {
151 : 0 : log_error("Non-LVM1 character device found at %s",
152 : : lvm1_group_path);
153 : : } else {
154 : 0 : _rm_blks(vg_path);
155 : :
156 : 0 : log_very_verbose("Removing %s", lvm1_group_path);
157 [ # # ]: 0 : if (unlink(lvm1_group_path) < 0)
158 : 0 : log_sys_error("unlink", lvm1_group_path);
159 : : }
160 : : }
161 : :
162 [ # # ]: 0 : if (!lstat(lv_path, &buf)) {
163 [ # # ][ # # ]: 0 : if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) {
164 : 0 : log_error("Symbolic link %s not created: file exists",
165 : : link_path);
166 : 0 : return 0;
167 : : }
168 : :
169 [ # # ][ # # ]: 0 : if (dm_udev_get_sync_support() && udev_checking() && check_udev) {
[ # # ]
170 : : /* Check udev created the correct link. */
171 [ # # # # ]: 0 : if (!stat(link_path, &buf_lp) &&
172 : 0 : !stat(lv_path, &buf)) {
173 [ # # ]: 0 : if (buf_lp.st_rdev == buf.st_rdev)
174 : 0 : return 1;
175 : : else
176 : 0 : log_warn("Symlink %s that should have been "
177 : : "created by udev does not have "
178 : : "correct target. Falling back to "
179 : : "direct link creation", lv_path);
180 : : } else
181 : 0 : log_warn("Symlink %s that should have been "
182 : : "created by udev could not be checked "
183 : : "for its correctness. Falling back to "
184 : : "direct link creation.", lv_path);
185 : :
186 : : }
187 : :
188 : 0 : log_very_verbose("Removing %s", lv_path);
189 [ # # ]: 0 : if (unlink(lv_path) < 0) {
190 : 0 : log_sys_error("unlink", lv_path);
191 : 0 : return 0;
192 : : }
193 [ # # ][ # # ]: 0 : } else if (dm_udev_get_sync_support() && udev_checking() && check_udev)
[ # # ]
194 : 0 : log_warn("The link %s should had been created by udev "
195 : : "but it was not found. Falling back to "
196 : : "direct link creation.", lv_path);
197 : :
198 : 0 : log_very_verbose("Linking %s -> %s", lv_path, link_path);
199 [ # # ]: 0 : if (symlink(link_path, lv_path) < 0) {
200 : 0 : log_sys_error("symlink", lv_path);
201 : 0 : return 0;
202 : : }
203 : :
204 [ # # ]: 0 : if (!dm_set_selinux_context(lv_path, S_IFLNK))
205 : 0 : return_0;
206 : :
207 : 0 : return 1;
208 : : }
209 : :
210 : 0 : static int _rm_link(const char *dev_dir, const char *vg_name,
211 : : const char *lv_name, int check_udev)
212 : : {
213 : : struct stat buf;
214 : : char lv_path[PATH_MAX];
215 : :
216 [ # # ]: 0 : if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
217 : : dev_dir, vg_name, lv_name) == -1) {
218 : 0 : log_error("Couldn't determine link pathname.");
219 : 0 : return 0;
220 : : }
221 : :
222 [ # # ][ # # ]: 0 : if (lstat(lv_path, &buf) && errno == ENOENT)
223 : 0 : return 1;
224 [ # # ][ # # ]: 0 : else if (dm_udev_get_sync_support() && udev_checking() && check_udev)
[ # # ]
225 : 0 : log_warn("The link %s should have been removed by udev "
226 : : "but it is still present. Falling back to "
227 : : "direct link removal.", lv_path);
228 : :
229 [ # # ]: 0 : if (!S_ISLNK(buf.st_mode)) {
230 : 0 : log_error("%s not symbolic link - not removing", lv_path);
231 : 0 : return 0;
232 : : }
233 : :
234 : 0 : log_very_verbose("Removing link %s", lv_path);
235 [ # # ]: 0 : if (unlink(lv_path) < 0) {
236 : 0 : log_sys_error("unlink", lv_path);
237 : 0 : return 0;
238 : : }
239 : :
240 : 0 : return 1;
241 : : }
242 : :
243 : : typedef enum {
244 : : FS_ADD,
245 : : FS_DEL,
246 : : FS_RENAME
247 : : } fs_op_t;
248 : :
249 : 0 : static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
250 : : const char *lv_name, const char *dev,
251 : : const char *old_lv_name, int check_udev)
252 : : {
253 [ # # # # ]: 0 : switch (type) {
254 : : case FS_ADD:
255 [ # # # # ]: 0 : if (!_mk_dir(dev_dir, vg_name) ||
256 : 0 : !_mk_link(dev_dir, vg_name, lv_name, dev, check_udev))
257 : 0 : return_0;
258 : 0 : break;
259 : : case FS_DEL:
260 [ # # # # ]: 0 : if (!_rm_link(dev_dir, vg_name, lv_name, check_udev) ||
261 : 0 : !_rm_dir(dev_dir, vg_name))
262 : 0 : return_0;
263 : 0 : break;
264 : : /* FIXME Use rename() */
265 : : case FS_RENAME:
266 [ # # ][ # # ]: 0 : if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name,
267 : : check_udev))
268 : 0 : stack;
269 : :
270 [ # # ]: 0 : if (!_mk_link(dev_dir, vg_name, lv_name, dev, check_udev))
271 : 0 : stack;
272 : : }
273 : :
274 : 0 : return 1;
275 : : }
276 : :
277 : : static DM_LIST_INIT(_fs_ops);
278 : :
279 : : struct fs_op_parms {
280 : : struct dm_list list;
281 : : fs_op_t type;
282 : : int check_udev;
283 : : char *dev_dir;
284 : : char *vg_name;
285 : : char *lv_name;
286 : : char *dev;
287 : : char *old_lv_name;
288 : : char names[0];
289 : : };
290 : :
291 : 0 : static void _store_str(char **pos, char **ptr, const char *str)
292 : : {
293 : 0 : strcpy(*pos, str);
294 : 0 : *ptr = *pos;
295 : 0 : *pos += strlen(*ptr) + 1;
296 : 0 : }
297 : :
298 : 0 : static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
299 : : const char *lv_name, const char *dev,
300 : : const char *old_lv_name, int check_udev)
301 : : {
302 : : struct fs_op_parms *fsp;
303 : 0 : size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
304 : 0 : strlen(dev) + strlen(old_lv_name) + 5;
305 : : char *pos;
306 : :
307 [ # # ]: 0 : if (!(fsp = dm_malloc(sizeof(*fsp) + len))) {
308 : 0 : log_error("No space to stack fs operation");
309 : 0 : return 0;
310 : : }
311 : :
312 : 0 : pos = fsp->names;
313 : 0 : fsp->type = type;
314 : 0 : fsp->check_udev = check_udev;
315 : :
316 : 0 : _store_str(&pos, &fsp->dev_dir, dev_dir);
317 : 0 : _store_str(&pos, &fsp->vg_name, vg_name);
318 : 0 : _store_str(&pos, &fsp->lv_name, lv_name);
319 : 0 : _store_str(&pos, &fsp->dev, dev);
320 : 0 : _store_str(&pos, &fsp->old_lv_name, old_lv_name);
321 : :
322 : 0 : dm_list_add(&_fs_ops, &fsp->list);
323 : :
324 : 0 : return 1;
325 : : }
326 : :
327 : 0 : static void _pop_fs_ops(void)
328 : : {
329 : : struct dm_list *fsph, *fspht;
330 : : struct fs_op_parms *fsp;
331 : :
332 [ # # ]: 0 : dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
333 : 0 : fsp = dm_list_item(fsph, struct fs_op_parms);
334 : 0 : _do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
335 : 0 : fsp->dev, fsp->old_lv_name, fsp->check_udev);
336 : 0 : dm_list_del(&fsp->list);
337 : 0 : dm_free(fsp);
338 : : }
339 : 0 : }
340 : :
341 : 0 : static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
342 : : const char *lv_name, const char *dev, const char *old_lv_name,
343 : : int check_udev)
344 : : {
345 [ # # ]: 0 : if (memlock()) {
346 [ # # ]: 0 : if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
347 : : old_lv_name, check_udev))
348 : 0 : return_0;
349 : 0 : return 1;
350 : : }
351 : :
352 : 0 : return _do_fs_op(type, dev_dir, vg_name, lv_name, dev,
353 : : old_lv_name, check_udev);
354 : : }
355 : :
356 : 0 : int fs_add_lv(const struct logical_volume *lv, const char *dev)
357 : : {
358 : 0 : return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
359 : 0 : dev, "", lv->vg->cmd->current_settings.udev_rules);
360 : : }
361 : :
362 : 0 : int fs_del_lv(const struct logical_volume *lv)
363 : : {
364 : 0 : return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
365 : 0 : "", "", lv->vg->cmd->current_settings.udev_rules);
366 : : }
367 : :
368 : 0 : int fs_del_lv_byname(const char *dev_dir, const char *vg_name,
369 : : const char *lv_name, int check_udev)
370 : : {
371 : 0 : return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", "", check_udev);
372 : : }
373 : :
374 : 0 : int fs_rename_lv(struct logical_volume *lv, const char *dev,
375 : : const char *old_vgname, const char *old_lvname)
376 : : {
377 [ # # ]: 0 : if (strcmp(old_vgname, lv->vg->name)) {
378 : 0 : return
379 [ # # # # ]: 0 : (_fs_op(FS_DEL, lv->vg->cmd->dev_dir, old_vgname,
380 : 0 : old_lvname, "", "", lv->vg->cmd->current_settings.udev_rules) &&
381 : 0 : _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name,
382 : 0 : lv->name, dev, "", lv->vg->cmd->current_settings.udev_rules));
383 : : }
384 : : else
385 : 0 : return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
386 : 0 : dev, old_lvname, lv->vg->cmd->current_settings.udev_rules);
387 : : }
388 : :
389 : 0 : void fs_unlock(void)
390 : : {
391 [ # # ]: 0 : if (!memlock()) {
392 : 0 : dm_lib_release();
393 : 0 : _pop_fs_ops();
394 : : }
395 : 0 : }
|