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