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