struct f2fs_fsck gfsck;
+static char *absolute_path(const char *file)
+{
+ char *ret;
+ char cwd[PATH_MAX];
+
+ if (file[0] != '/') {
+ if (getcwd(cwd, PATH_MAX) == NULL) {
+ fprintf(stderr, "Failed to getcwd\n");
+ exit(EXIT_FAILURE);
+ }
+ ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
+ if (ret)
+ sprintf(ret, "%s/%s", cwd, file);
+ } else
+ ret = strdup(file);
+ return ret;
+}
+
void fsck_usage()
{
MSG(0, "\nUsage: fsck.f2fs [options] device\n");
{
MSG(0, "\nUsage: sload.f2fs [options] device\n");
MSG(0, "[options]:\n");
+ MSG(0, " -C fs_config\n");
MSG(0, " -f source directory [path of the source directory]\n");
+ MSG(0, " -p product out directory\n");
+ MSG(0, " -s file_contexts\n");
MSG(0, " -t mount point [prefix of target fs path, default:/]\n");
+ MSG(0, " -T timestamp\n");
MSG(0, " -d debug level [default:0]\n");
exit(1);
}
break;
}
} else if (!strcmp("sload.f2fs", prog)) {
- const char *option_string = "d:f:t:";
+ const char *option_string = "C:d:f:p:s:t:T:";
+#ifdef HAVE_LIBSELINUX
+ int max_nr_opt = (int)sizeof(c.seopt_file) /
+ sizeof(c.seopt_file[0]);
+ char *token;
+#endif
+ char *p;
c.func = SLOAD;
while ((option = getopt(argc, argv, option_string)) != EOF) {
switch (option) {
+ case 'C':
+ c.fs_config_file = absolute_path(optarg);
+ break;
case 'd':
if (!is_digits(optarg)) {
err = EWRONG_OPT;
c.dbg_lv);
break;
case 'f':
- c.from_dir = (char *)optarg;
+ c.from_dir = absolute_path(optarg);
+ break;
+ case 'p':
+ c.target_out_dir = absolute_path(optarg);
+ break;
+ case 's':
+#ifdef HAVE_LIBSELINUX
+ token = strtok(optarg, ",");
+ while (token) {
+ if (c.nr_opt == max_nr_opt) {
+ MSG(0, "\tError: Expected at most %d selinux opts\n",
+ max_nr_opt);
+ error_out(prog);
+ }
+ c.seopt_file[c.nr_opt].type =
+ SELABEL_OPT_PATH;
+ c.seopt_file[c.nr_opt].value =
+ absolute_path(token);
+ c.nr_opt++;
+ token = strtok(NULL, ",");
+ }
+#else
+ MSG(0, "Info: Not support selinux opts\n");
+#endif
break;
case 't':
c.mount_point = (char *)optarg;
break;
+ case 'T':
+ c.fixed_time = strtoul(optarg, &p, 0);
+ break;
default:
err = EUNKNOWN_OPT;
break;
static int do_sload(struct f2fs_sb_info *sbi)
{
if (!c.from_dir) {
- MSG(0, "\tError: Need source directory\n");
- sload_usage();
- return -1;
+ MSG(0, "Info: No source directory, but it's okay.\n");
+ return 0;
}
if (!c.mount_point)
c.mount_point = "/";
- return f2fs_sload(sbi, c.from_dir, c.mount_point, NULL, NULL);
+ return f2fs_sload(sbi);
}
int main(int argc, char **argv)
#endif
#ifdef WITH_SLOAD
case SLOAD:
- do_sload(sbi);
- break;
+ if (do_sload(sbi))
+ goto out_err;
+
+ f2fs_do_umount(sbi);
+
+ /* fsck to fix missing quota */
+ c.func = FSCK;
+ c.fix_on = 1;
+ goto fsck_again;
#endif
default:
ERR_MSG("Wrong program name\n");
#endif
#ifdef HAVE_LIBSELINUX
-#include <selinux/selinux.h>
-#include <selinux/label.h>
+static struct selabel_handle *sehnd = NULL;
#endif
+typedef void (*fs_config_f)(const char *path, int dir,
+ const char *target_out_path,
+ unsigned *uid, unsigned *gid,
+ unsigned *mode, uint64_t *capabilities);
+
+static fs_config_f fs_config_func = NULL;
+
#ifdef WITH_ANDROID
-#include <selinux/label.h>
+#include <selinux/android.h>
#include <private/android_filesystem_config.h>
-
-static void handle_selabel(struct dentry *de, int dir, char *target_out)
-{
- uint64_t capabilities;
- unsigned int mode = 0;
- unsigned int uid = 0;
- unsigned int gid = 0;
-
- fs_config(de->path, dir, target_out, &uid,
- &gid, &mode, &capabilities);
- de->mode = mode;
- de->uid = uid;
- de->gid = gid;
- de->capabilities = capabilities;
-}
-#else
-#define handle_selabel(...)
+#include <private/canned_fs_config.h>
#endif
static int filter_dot(const struct dirent *d)
}
}
+#ifdef HAVE_LIBSELINUX
+static int set_selinux_xattr(struct f2fs_sb_info *sbi, const char *path,
+ nid_t ino, int mode)
+{
+ char *secontext = NULL;
+ char *mnt_path = NULL;
+
+ if (!sehnd)
+ return 0;
+
+ if (asprintf(&mnt_path, "%s%s", c.mount_point, path) <= 0) {
+ ERR_MSG("cannot allocate security path for %s%s\n",
+ c.mount_point, path);
+ return -ENOMEM;
+ }
+
+ /* set root inode selinux context */
+ if (selabel_lookup(sehnd, &secontext, mnt_path, mode) < 0) {
+ ERR_MSG("cannot lookup security context for %s\n", mnt_path);
+ free(mnt_path);
+ return -EINVAL;
+ }
+
+ if (secontext) {
+ MSG(2, "%s (%d) -> SELinux context = %s\n",
+ mnt_path, ino, secontext);
+ inode_set_selinux(sbi, ino, secontext);
+ }
+ freecon(secontext);
+ free(mnt_path);
+ return 0;
+}
+#else
+#define set_selinux_xattr(...) 0
+#endif
+
+static int set_perms_and_caps(struct dentry *de)
+{
+ uint64_t capabilities = 0;
+ unsigned int uid = 0, gid = 0, imode = 0;
+ char *mnt_path = NULL;
+
+ if (asprintf(&mnt_path, "%s%s", c.mount_point, de->path) <= 0) {
+ ERR_MSG("cannot allocate mount path for %s%s\n",
+ c.mount_point, de->path);
+ return -ENOMEM;
+ }
+
+ /* Permissions */
+ if (fs_config_func != NULL) {
+ fs_config_func(mnt_path, S_ISDIR(de->mode),
+ c.target_out_dir, &uid, &gid, &imode,
+ &capabilities);
+ de->uid = uid & 0xffff;
+ de->gid = gid & 0xffff;
+ de->mode = (de->mode & S_IFMT) | (imode & 0xffff);
+ de->capabilities = capabilities;
+ }
+ MSG(2, "%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, "
+ "capabilities = 0x%"PRIx64"\n",
+ mnt_path, de->mode, de->uid, de->gid, de->capabilities);
+ free(mnt_path);
+ return 0;
+}
+
+static void set_inode_metadata(struct dentry *de)
+{
+ struct stat stat;
+ int ret;
+
+ ret = lstat(de->full_path, &stat);
+ if (ret < 0) {
+ ERR_MSG("lstat failure\n");
+ ASSERT(0);
+ }
+
+ if (S_ISREG(stat.st_mode)) {
+ de->file_type = F2FS_FT_REG_FILE;
+ } else if (S_ISDIR(stat.st_mode)) {
+ de->file_type = F2FS_FT_DIR;
+ } else if (S_ISCHR(stat.st_mode)) {
+ de->file_type = F2FS_FT_CHRDEV;
+ } else if (S_ISBLK(stat.st_mode)) {
+ de->file_type = F2FS_FT_BLKDEV;
+ } else if (S_ISFIFO(stat.st_mode)) {
+ de->file_type = F2FS_FT_FIFO;
+ } else if (S_ISSOCK(stat.st_mode)) {
+ de->file_type = F2FS_FT_SOCK;
+ } else if (S_ISLNK(stat.st_mode)) {
+ de->file_type = F2FS_FT_SYMLINK;
+ de->link = calloc(F2FS_BLKSIZE, 1);
+ ASSERT(de->link);
+ ret = readlink(de->full_path, de->link, F2FS_BLKSIZE - 1);
+ ASSERT(ret >= 0);
+ } else {
+ ERR_MSG("unknown file type on %s", de->path);
+ ASSERT(0);
+ }
+
+ de->size = stat.st_size;
+ de->mode = stat.st_mode &
+ (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
+ if (c.fixed_time == -1 && c.from_dir)
+ de->mtime = stat.st_mtime;
+ else
+ de->mtime = c.fixed_time;
+
+ set_perms_and_caps(de);
+}
+
static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
const char *dir_path, const char *target_out_dir,
- nid_t dir_ino, struct selabel_handle *sehnd)
+ nid_t dir_ino)
{
int entries = 0;
struct dentry *dentries;
struct dirent **namelist = NULL;
- struct stat stat;
int i, ret = 0;
entries = scandir(full_path, &namelist, filter_dot, (void *)alphasort);
}
dentries[i].len = strlen((char *)dentries[i].name);
- ret = asprintf(&dentries[i].path, "%s/%s",
+ ret = asprintf(&dentries[i].path, "%s%s",
dir_path, namelist[i]->d_name);
ASSERT(ret > 0);
ret = asprintf(&dentries[i].full_path, "%s/%s",
ASSERT(ret > 0);
free(namelist[i]);
- ret = lstat(dentries[i].full_path, &stat);
- if (ret < 0) {
- ERR_MSG("Skip: lstat failure\n");
- continue;
- }
- dentries[i].size = stat.st_size;
- dentries[i].mode = stat.st_mode &
- (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
- dentries[i].mtime = stat.st_mtime;
-
- handle_selabel(dentries + i, S_ISDIR(stat.st_mode),
- target_out_dir);
-
-#ifdef HAVE_LIBSELINUX
- if (sehnd && selabel_lookup(sehnd, &dentries[i].secon,
- dentries[i].path, stat.st_mode) < 0)
- ERR_MSG("Cannot lookup security context for %s\n",
- dentries[i].path);
-#endif
+ set_inode_metadata(dentries + i);
dentries[i].pino = dir_ino;
-
- if (S_ISREG(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_REG_FILE;
- } else if (S_ISDIR(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_DIR;
- } else if (S_ISCHR(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_CHRDEV;
- } else if (S_ISBLK(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_BLKDEV;
- } else if (S_ISFIFO(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_FIFO;
- } else if (S_ISSOCK(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_SOCK;
- } else if (S_ISLNK(stat.st_mode)) {
- dentries[i].file_type = F2FS_FT_SYMLINK;
- dentries[i].link = calloc(F2FS_BLKSIZE, 1);
- ASSERT(dentries[i].link);
- ret = readlink(dentries[i].full_path,
- dentries[i].link, F2FS_BLKSIZE - 1);
- ASSERT(ret >= 0);
- } else {
- MSG(1, "unknown file type on %s", dentries[i].path);
- i--;
- entries--;
- }
}
free(namelist);
f2fs_build_file(sbi, dentries + i);
} else if (dentries[i].file_type == F2FS_FT_DIR) {
char *subdir_full_path = NULL;
- char *subdir_dir_path;
+ char *subdir_dir_path = NULL;
- ret = asprintf(&subdir_full_path, "%s/",
+ ret = asprintf(&subdir_full_path, "%s",
dentries[i].full_path);
ASSERT(ret > 0);
ret = asprintf(&subdir_dir_path, "%s/",
ASSERT(ret > 0);
build_directory(sbi, subdir_full_path, subdir_dir_path,
- target_out_dir, dentries[i].ino, sehnd);
+ target_out_dir, dentries[i].ino);
free(subdir_full_path);
free(subdir_dir_path);
} else if (dentries[i].file_type == F2FS_FT_SYMLINK) {
MSG(1, "Error unknown file type\n");
}
-#ifdef HAVE_LIBSELINUX
- if (dentries[i].secon) {
- inode_set_selinux(sbi, dentries[i].ino, dentries[i].secon);
- MSG(1, "File = %s \n----->SELinux context = %s\n",
- dentries[i].path, dentries[i].secon);
- MSG(1, "----->mode = 0x%x, uid = 0x%x, gid = 0x%x, "
- "capabilities = 0x%lx \n",
- dentries[i].mode, dentries[i].uid,
- dentries[i].gid, dentries[i].capabilities);
- }
-
- free(dentries[i].secon);
-#endif
+ ret = set_selinux_xattr(sbi, dentries[i].path,
+ dentries[i].ino, dentries[i].mode);
+ if (ret)
+ return ret;
free(dentries[i].path);
free(dentries[i].full_path);
return 0;
}
-int f2fs_sload(struct f2fs_sb_info *sbi, const char *from_dir,
- const char *mount_point,
- const char *target_out_dir,
- struct selabel_handle *sehnd)
+static int configure_files(void)
{
- int ret = 0;
- nid_t mnt_ino = F2FS_ROOT_INO(sbi);
+#ifdef HAVE_LIBSELINUX
+ if (!c.nr_opt)
+ goto skip;
+#if !defined(__ANDROID__)
+ sehnd = selabel_open(SELABEL_CTX_FILE, c.seopt_file, c.nr_opt);
+ if (!sehnd) {
+ ERR_MSG("Failed to open file contexts \"%s\"",
+ c.seopt_file[0].value);
+ return -EINVAL;
+ }
+#else
+ sehnd = selinux_android_file_context_handle();
+ if (!sehnd) {
+ ERR_MSG("Failed to get android file_contexts\n", c.mount_point);
+ return -EINVAL;
+ }
+#endif
+skip:
+#endif
+#ifdef WITH_ANDROID
+ /* Load the FS config */
+ if (c.fs_config_file) {
+ int ret = load_canned_fs_config(c.fs_config_file);
- /* flush NAT/SIT journal entries */
- flush_journal_entries(sbi);
+ if (ret < 0) {
+ ERR_MSG("Failed to load fs_config \"%s\"",
+ c.fs_config_file);
+ return ret;
+ }
+ fs_config_func = canned_fs_config;
+ } else {
+ fs_config_func = fs_config;
+ }
+#endif
+ return 0;
+}
- ret = f2fs_find_path(sbi, (char *)mount_point, &mnt_ino);
+int f2fs_sload(struct f2fs_sb_info *sbi)
+{
+ int ret = 0;
+
+ ret = configure_files();
if (ret) {
- ERR_MSG("Failed to get mount point %s\n", mount_point);
+ ERR_MSG("Failed to configure files\n");
return ret;
}
- ret = build_directory(sbi, from_dir, mount_point, target_out_dir,
- mnt_ino, sehnd);
+ /* flush NAT/SIT journal entries */
+ flush_journal_entries(sbi);
+
+ ret = build_directory(sbi, c.from_dir, "/",
+ c.target_out_dir, F2FS_ROOT_INO(sbi));
if (ret) {
ERR_MSG("Failed to build due to %d\n", ret);
return ret;
}
-#ifdef HAVE_LIBSELINUX
- if (sehnd) {
- char *secontext = NULL;
-
- /* set root inode selinux context */
- if (selabel_lookup(sehnd, &secontext, mount_point, S_IFDIR) < 0)
- ERR_MSG("cannot lookup security context for %s\n",
- mount_point);
- if (secontext) {
- MSG(1, "Labeling %s as %s, root_ino = %d\n",
- mount_point, secontext, F2FS_ROOT_INO(sbi));
- /* xattr_add for root inode */
- inode_set_selinux(sbi, F2FS_ROOT_INO(sbi), secontext);
- }
- free(secontext);
+ ret = set_selinux_xattr(sbi, c.mount_point,
+ F2FS_ROOT_INO(sbi), S_IFDIR);
+ if (ret) {
+ ERR_MSG("Failed to set selinux for root: %d\n", ret);
+ return ret;
}
-#endif
/* update curseg info; can update sit->types */
move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);