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