1 /**
2 * sload.c
3 *
4 * Copyright (C) 2015 Huawei Ltd.
5 * Witten by:
6 * Hou Pengyang <houpengyang@huawei.com>
7 * Liu Shuoran <liushuoran@huawei.com>
8 * Jaegeuk Kim <jaegeuk@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
filter_dot(const struct dirent * d)39 static int filter_dot(const struct dirent *d)
40 {
41 return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
42 }
43
f2fs_make_directory(struct f2fs_sb_info * sbi,int entries,struct dentry * de)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
set_selinux_xattr(struct f2fs_sb_info * sbi,const char * path,nid_t ino,int mode)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
set_perms_and_caps(struct dentry * de)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
set_inode_metadata(struct dentry * de)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
build_directory(struct f2fs_sb_info * sbi,const char * full_path,const char * dir_path,const char * target_out_dir,nid_t dir_ino)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
configure_files(void)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
f2fs_sload(struct f2fs_sb_info * sbi)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, 0);
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