fs.c revision 1.1.1.2 1 /* $NetBSD: fs.c,v 1.1.1.2 2009/02/18 11:16:51 haad 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 }
105 }
106
107 static int _mk_link(const char *dev_dir, const char *vg_name,
108 const char *lv_name, const char *dev)
109 {
110 char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
111 char vg_path[PATH_MAX];
112 struct stat buf;
113
114 if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
115 dev_dir, vg_name) == -1) {
116 log_error("Couldn't create path for volume group dir %s",
117 vg_name);
118 return 0;
119 }
120
121 if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
122 lv_name) == -1) {
123 log_error("Couldn't create source pathname for "
124 "logical volume link %s", lv_name);
125 return 0;
126 }
127
128 if (dm_snprintf(link_path, sizeof(link_path), "%s/%s",
129 dm_dir(), dev) == -1) {
130 log_error("Couldn't create destination pathname for "
131 "logical volume link for %s", lv_name);
132 return 0;
133 }
134
135 if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
136 vg_path) == -1) {
137 log_error("Couldn't create pathname for LVM1 group file for %s",
138 vg_name);
139 return 0;
140 }
141
142 /* To reach this point, the VG must have been locked.
143 * As locking fails if the VG is active under LVM1, it's
144 * now safe to remove any LVM1 devices we find here
145 * (as well as any existing LVM2 symlink). */
146 if (!lstat(lvm1_group_path, &buf)) {
147 if (!S_ISCHR(buf.st_mode)) {
148 log_error("Non-LVM1 character device found at %s",
149 lvm1_group_path);
150 } else {
151 _rm_blks(vg_path);
152
153 log_very_verbose("Removing %s", lvm1_group_path);
154 if (unlink(lvm1_group_path) < 0)
155 log_sys_error("unlink", lvm1_group_path);
156 }
157 }
158
159 if (!lstat(lv_path, &buf)) {
160 if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) {
161 log_error("Symbolic link %s not created: file exists",
162 link_path);
163 return 0;
164 }
165
166 log_very_verbose("Removing %s", lv_path);
167 if (unlink(lv_path) < 0) {
168 log_sys_error("unlink", lv_path);
169 return 0;
170 }
171 }
172
173 log_very_verbose("Linking %s -> %s", lv_path, link_path);
174 if (symlink(link_path, lv_path) < 0) {
175 log_sys_error("symlink", lv_path);
176 return 0;
177 }
178
179 #ifdef HAVE_SELINUX
180 if (!dm_set_selinux_context(lv_path, S_IFLNK))
181 return_0;
182 #endif
183
184 return 1;
185 }
186
187 static int _rm_link(const char *dev_dir, const char *vg_name,
188 const char *lv_name)
189 {
190 struct stat buf;
191 char lv_path[PATH_MAX];
192
193 if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
194 dev_dir, vg_name, lv_name) == -1) {
195 log_error("Couldn't determine link pathname.");
196 return 0;
197 }
198
199 if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
200 if (errno == ENOENT)
201 return 1;
202 log_error("%s not symbolic link - not removing", lv_path);
203 return 0;
204 }
205
206 log_very_verbose("Removing link %s", lv_path);
207 if (unlink(lv_path) < 0) {
208 log_sys_error("unlink", lv_path);
209 return 0;
210 }
211
212 return 1;
213 }
214
215 typedef enum {
216 FS_ADD,
217 FS_DEL,
218 FS_RENAME
219 } fs_op_t;
220
221 static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
222 const char *lv_name, const char *dev,
223 const char *old_lv_name)
224 {
225 switch (type) {
226 case FS_ADD:
227 if (!_mk_dir(dev_dir, vg_name) ||
228 !_mk_link(dev_dir, vg_name, lv_name, dev))
229 return_0;
230 break;
231 case FS_DEL:
232 if (!_rm_link(dev_dir, vg_name, lv_name) ||
233 !_rm_dir(dev_dir, vg_name))
234 return_0;
235 break;
236 /* FIXME Use rename() */
237 case FS_RENAME:
238 if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name))
239 stack;
240
241 if (!_mk_link(dev_dir, vg_name, lv_name, dev))
242 stack;
243 }
244
245 return 1;
246 }
247
248 static DM_LIST_INIT(_fs_ops);
249
250 struct fs_op_parms {
251 struct dm_list list;
252 fs_op_t type;
253 char *dev_dir;
254 char *vg_name;
255 char *lv_name;
256 char *dev;
257 char *old_lv_name;
258 char names[0];
259 };
260
261 static void _store_str(char **pos, char **ptr, const char *str)
262 {
263 strcpy(*pos, str);
264 *ptr = *pos;
265 *pos += strlen(*ptr) + 1;
266 }
267
268 static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
269 const char *lv_name, const char *dev,
270 const char *old_lv_name)
271 {
272 struct fs_op_parms *fsp;
273 size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
274 strlen(dev) + strlen(old_lv_name) + 5;
275 char *pos;
276
277 if (!(fsp = dm_malloc(sizeof(*fsp) + len))) {
278 log_error("No space to stack fs operation");
279 return 0;
280 }
281
282 pos = fsp->names;
283 fsp->type = type;
284
285 _store_str(&pos, &fsp->dev_dir, dev_dir);
286 _store_str(&pos, &fsp->vg_name, vg_name);
287 _store_str(&pos, &fsp->lv_name, lv_name);
288 _store_str(&pos, &fsp->dev, dev);
289 _store_str(&pos, &fsp->old_lv_name, old_lv_name);
290
291 dm_list_add(&_fs_ops, &fsp->list);
292
293 return 1;
294 }
295
296 static void _pop_fs_ops(void)
297 {
298 struct dm_list *fsph, *fspht;
299 struct fs_op_parms *fsp;
300
301 dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
302 fsp = dm_list_item(fsph, struct fs_op_parms);
303 _do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
304 fsp->dev, fsp->old_lv_name);
305 dm_list_del(&fsp->list);
306 dm_free(fsp);
307 }
308 }
309
310 static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
311 const char *lv_name, const char *dev, const char *old_lv_name)
312 {
313 if (memlock()) {
314 if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
315 old_lv_name))
316 return_0;
317 return 1;
318 }
319
320 return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name);
321 }
322
323 int fs_add_lv(const struct logical_volume *lv, const char *dev)
324 {
325 return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
326 dev, "");
327 }
328
329 int fs_del_lv(const struct logical_volume *lv)
330 {
331 return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
332 "", "");
333 }
334
335 int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name)
336 {
337 return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", "");
338 }
339
340 int fs_rename_lv(struct logical_volume *lv, const char *dev,
341 const char *old_vgname, const char *old_lvname)
342 {
343 if (strcmp(old_vgname, lv->vg->name)) {
344 return
345 (_fs_op(FS_DEL, lv->vg->cmd->dev_dir, old_vgname, old_lvname, "", "") &&
346 _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, dev, ""));
347 }
348 else
349 return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
350 dev, old_lvname);
351 }
352
353 void fs_unlock(void)
354 {
355 if (!memlock()) {
356 dm_lib_release();
357 _pop_fs_ops();
358 }
359 }
360