1 /** 2 * sload.c 3 * 4 * Copyright (C) 2015 Huawei Ltd. 5 * Witten by: 6 * Hou Pengyang <houpengyang (at) huawei.com> 7 * Liu Shuoran <liushuoran (at) huawei.com> 8 * Jaegeuk Kim <jaegeuk (at) kernel.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 #define _GNU_SOURCE 15 #include "fsck.h" 16 #include <libgen.h> 17 #include <dirent.h> 18 #ifdef HAVE_MNTENT_H 19 #include <mntent.h> 20 #endif 21 22 #ifdef HAVE_LIBSELINUX 23 static struct selabel_handle *sehnd = NULL; 24 #endif 25 26 typedef void (*fs_config_f)(const char *path, int dir, 27 const char *target_out_path, 28 unsigned *uid, unsigned *gid, 29 unsigned *mode, uint64_t *capabilities); 30 31 static fs_config_f fs_config_func = NULL; 32 33 #ifdef WITH_ANDROID 34 #include <selinux/android.h> 35 #include <private/android_filesystem_config.h> 36 #include <private/canned_fs_config.h> 37 #endif 38 39 static int filter_dot(const struct dirent *d) 40 { 41 return (strcmp(d->d_name, "..") && strcmp(d->d_name, ".")); 42 } 43 44 static void f2fs_make_directory(struct f2fs_sb_info *sbi, 45 int entries, struct dentry *de) 46 { 47 int i = 0; 48 49 for (i = 0; i < entries; i++) { 50 if (de[i].file_type == F2FS_FT_DIR) 51 f2fs_mkdir(sbi, de + i); 52 else if (de[i].file_type == F2FS_FT_REG_FILE) 53 f2fs_create(sbi, de + i); 54 else if (de[i].file_type == F2FS_FT_SYMLINK) 55 f2fs_symlink(sbi, de + i); 56 } 57 } 58 59 #ifdef HAVE_LIBSELINUX 60 static int set_selinux_xattr(struct f2fs_sb_info *sbi, const char *path, 61 nid_t ino, int mode) 62 { 63 char *secontext = NULL; 64 char *mnt_path = NULL; 65 66 if (!sehnd) 67 return 0; 68 69 if (asprintf(&mnt_path, "%s%s", c.mount_point, path) <= 0) { 70 ERR_MSG("cannot allocate security path for %s%s\n", 71 c.mount_point, path); 72 return -ENOMEM; 73 } 74 75 /* set root inode selinux context */ 76 if (selabel_lookup(sehnd, &secontext, mnt_path, mode) < 0) { 77 ERR_MSG("cannot lookup security context for %s\n", mnt_path); 78 free(mnt_path); 79 return -EINVAL; 80 } 81 82 if (secontext) { 83 MSG(2, "%s (%d) -> SELinux context = %s\n", 84 mnt_path, ino, secontext); 85 inode_set_selinux(sbi, ino, secontext); 86 } 87 freecon(secontext); 88 free(mnt_path); 89 return 0; 90 } 91 #else 92 #define set_selinux_xattr(...) 0 93 #endif 94 95 static int set_perms_and_caps(struct dentry *de) 96 { 97 uint64_t capabilities = 0; 98 unsigned int uid = 0, gid = 0, imode = 0; 99 char *mnt_path = NULL; 100 101 if (asprintf(&mnt_path, "%s%s", c.mount_point, de->path) <= 0) { 102 ERR_MSG("cannot allocate mount path for %s%s\n", 103 c.mount_point, de->path); 104 return -ENOMEM; 105 } 106 107 /* Permissions */ 108 if (fs_config_func != NULL) { 109 fs_config_func(mnt_path, de->file_type == F2FS_FT_DIR, 110 c.target_out_dir, &uid, &gid, &imode, 111 &capabilities); 112 de->uid = uid & 0xffff; 113 de->gid = gid & 0xffff; 114 de->mode = (de->mode & S_IFMT) | (imode & 0xffff); 115 de->capabilities = capabilities; 116 } 117 MSG(2, "%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, " 118 "capabilities = 0x%"PRIx64"\n", 119 mnt_path, de->mode, de->uid, de->gid, de->capabilities); 120 free(mnt_path); 121 return 0; 122 } 123 124 static void set_inode_metadata(struct dentry *de) 125 { 126 struct stat stat; 127 int ret; 128 129 ret = lstat(de->full_path, &stat); 130 if (ret < 0) { 131 ERR_MSG("lstat failure\n"); 132 ASSERT(0); 133 } 134 135 if (S_ISREG(stat.st_mode)) { 136 de->file_type = F2FS_FT_REG_FILE; 137 } else if (S_ISDIR(stat.st_mode)) { 138 de->file_type = F2FS_FT_DIR; 139 } else if (S_ISCHR(stat.st_mode)) { 140 de->file_type = F2FS_FT_CHRDEV; 141 } else if (S_ISBLK(stat.st_mode)) { 142 de->file_type = F2FS_FT_BLKDEV; 143 } else if (S_ISFIFO(stat.st_mode)) { 144 de->file_type = F2FS_FT_FIFO; 145 } else if (S_ISSOCK(stat.st_mode)) { 146 de->file_type = F2FS_FT_SOCK; 147 } else if (S_ISLNK(stat.st_mode)) { 148 de->file_type = F2FS_FT_SYMLINK; 149 de->link = calloc(F2FS_BLKSIZE, 1); 150 ASSERT(de->link); 151 ret = readlink(de->full_path, de->link, F2FS_BLKSIZE - 1); 152 ASSERT(ret >= 0); 153 } else { 154 ERR_MSG("unknown file type on %s", de->path); 155 ASSERT(0); 156 } 157 158 de->size = stat.st_size; 159 de->mode = stat.st_mode & 160 (S_IFMT|S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); 161 if (c.fixed_time == -1 && c.from_dir) 162 de->mtime = stat.st_mtime; 163 else 164 de->mtime = c.fixed_time; 165 166 set_perms_and_caps(de); 167 } 168 169 static int build_directory(struct f2fs_sb_info *sbi, const char *full_path, 170 const char *dir_path, const char *target_out_dir, 171 nid_t dir_ino) 172 { 173 int entries = 0; 174 struct dentry *dentries; 175 struct dirent **namelist = NULL; 176 int i, ret = 0; 177 178 entries = scandir(full_path, &namelist, filter_dot, (void *)alphasort); 179 if (entries < 0) { 180 ERR_MSG("No entries in %s\n", full_path); 181 return -ENOENT; 182 } 183 184 dentries = calloc(entries, sizeof(struct dentry)); 185 if (dentries == NULL) 186 return -ENOMEM; 187 188 for (i = 0; i < entries; i++) { 189 dentries[i].name = (unsigned char *)strdup(namelist[i]->d_name); 190 if (dentries[i].name == NULL) { 191 ERR_MSG("Skip: ENOMEM\n"); 192 continue; 193 } 194 dentries[i].len = strlen((char *)dentries[i].name); 195 196 ret = asprintf(&dentries[i].path, "%s%s", 197 dir_path, namelist[i]->d_name); 198 ASSERT(ret > 0); 199 ret = asprintf(&dentries[i].full_path, "%s/%s", 200 full_path, namelist[i]->d_name); 201 ASSERT(ret > 0); 202 free(namelist[i]); 203 204 set_inode_metadata(dentries + i); 205 206 dentries[i].pino = dir_ino; 207 } 208 209 free(namelist); 210 211 f2fs_make_directory(sbi, entries, dentries); 212 213 for (i = 0; i < entries; i++) { 214 if (dentries[i].file_type == F2FS_FT_REG_FILE) { 215 f2fs_build_file(sbi, dentries + i); 216 } else if (dentries[i].file_type == F2FS_FT_DIR) { 217 char *subdir_full_path = NULL; 218 char *subdir_dir_path = NULL; 219 220 ret = asprintf(&subdir_full_path, "%s", 221 dentries[i].full_path); 222 ASSERT(ret > 0); 223 ret = asprintf(&subdir_dir_path, "%s/", 224 dentries[i].path); 225 ASSERT(ret > 0); 226 227 build_directory(sbi, subdir_full_path, subdir_dir_path, 228 target_out_dir, dentries[i].ino); 229 free(subdir_full_path); 230 free(subdir_dir_path); 231 } else if (dentries[i].file_type == F2FS_FT_SYMLINK) { 232 /* 233 * It is already done in f2fs_make_directory 234 * f2fs_make_symlink(sbi, dir_ino, &dentries[i]); 235 */ 236 } else { 237 MSG(1, "Error unknown file type\n"); 238 } 239 240 ret = set_selinux_xattr(sbi, dentries[i].path, 241 dentries[i].ino, dentries[i].mode); 242 if (ret) 243 return ret; 244 245 free(dentries[i].path); 246 free(dentries[i].full_path); 247 free((void *)dentries[i].name); 248 } 249 250 free(dentries); 251 return 0; 252 } 253 254 static int configure_files(void) 255 { 256 #ifdef HAVE_LIBSELINUX 257 if (!c.nr_opt) 258 goto skip; 259 #if !defined(__ANDROID__) 260 sehnd = selabel_open(SELABEL_CTX_FILE, c.seopt_file, c.nr_opt); 261 if (!sehnd) { 262 ERR_MSG("Failed to open file contexts \"%s\"", 263 c.seopt_file[0].value); 264 return -EINVAL; 265 } 266 #else 267 sehnd = selinux_android_file_context_handle(); 268 if (!sehnd) { 269 ERR_MSG("Failed to get android file_contexts\n", c.mount_point); 270 return -EINVAL; 271 } 272 #endif 273 skip: 274 #endif 275 #ifdef WITH_ANDROID 276 /* Load the FS config */ 277 if (c.fs_config_file) { 278 int ret = load_canned_fs_config(c.fs_config_file); 279 280 if (ret < 0) { 281 ERR_MSG("Failed to load fs_config \"%s\"", 282 c.fs_config_file); 283 return ret; 284 } 285 fs_config_func = canned_fs_config; 286 } else { 287 fs_config_func = fs_config; 288 } 289 #endif 290 return 0; 291 } 292 293 int f2fs_sload(struct f2fs_sb_info *sbi) 294 { 295 int ret = 0; 296 297 ret = configure_files(); 298 if (ret) { 299 ERR_MSG("Failed to configure files\n"); 300 return ret; 301 } 302 303 /* flush NAT/SIT journal entries */ 304 flush_journal_entries(sbi); 305 306 ret = build_directory(sbi, c.from_dir, "/", 307 c.target_out_dir, F2FS_ROOT_INO(sbi)); 308 if (ret) { 309 ERR_MSG("Failed to build due to %d\n", ret); 310 return ret; 311 } 312 313 ret = set_selinux_xattr(sbi, c.mount_point, 314 F2FS_ROOT_INO(sbi), S_IFDIR); 315 if (ret) { 316 ERR_MSG("Failed to set selinux for root: %d\n", ret); 317 return ret; 318 } 319 320 /* update curseg info; can update sit->types */ 321 move_curseg_info(sbi, SM_I(sbi)->main_blkaddr); 322 zero_journal_entries(sbi); 323 write_curseg_info(sbi); 324 325 /* flush dirty sit entries */ 326 flush_sit_entries(sbi); 327 328 write_checkpoint(sbi); 329 return 0; 330 } 331