/* This function takes three parameters: PATH of an existing file system object. A RECURSE boolean which if the file system object is a directory, will call restorecon_private on every file system object in the directory. A LOCAL boolean that indicates whether the function should set object labels to the default for the local process, or use system wide settings. Returns false on failure. errno will be set appropriately. */ bool restorecon (char const *path, bool recurse, bool local) { char *newpath = NULL; FTS *fts; bool ok = true; if (! IS_ABSOLUTE_FILE_NAME (path) && ! local) { /* Generate absolute path as required by subsequent matchpathcon(), with libselinux < 2.1.5 2011-0826. Also generating the absolute path before the fts walk, will generate absolute paths in the fts entries, which may be quicker to process in any case. */ newpath = canonicalize_filename_mode (path, CAN_MISSING); if (! newpath) error (EXIT_FAILURE, errno, _("error canonicalizing %s"), quote (path)); } const char *ftspath[2] = { newpath ? newpath : path, NULL }; if (! recurse) { ok = restorecon_private (*ftspath, local) != -1; free (newpath); return ok; } fts = xfts_open ((char *const *) ftspath, FTS_PHYSICAL, NULL); while (1) { FTSENT *ent; ent = fts_read (fts); if (ent == NULL) { if (errno != 0) { error (0, errno, _("fts_read failed")); ok = false; } break; } ok &= restorecon_private (fts->fts_path, local) != -1; } if (fts_close (fts) != 0) { error (0, errno, _("fts_close failed")); ok = false; } free (newpath); return ok; }
/* Remove FILEs, honoring options specified via X. Return RM_OK if successful. */ enum RM_status rm (char *const *file, struct rm_options const *x) { enum RM_status rm_status = RM_OK; if (*file) { int bit_flags = (FTS_CWDFD | FTS_NOSTAT | FTS_PHYSICAL); if (x->one_file_system) bit_flags |= FTS_XDEV; FTS *fts = xfts_open (file, bit_flags, NULL); while (1) { FTSENT *ent; ent = fts_read (fts); if (ent == NULL) { if (errno != 0) { error (0, errno, _("fts_read failed")); rm_status = RM_ERROR; } break; } enum RM_status s = rm_fts (fts, ent, x); assert (VALID_STATUS (s)); UPDATE_STATUS (rm_status, s); } if (fts_close (fts) != 0) { error (0, errno, _("fts_close failed")); rm_status = RM_ERROR; } } return rm_status; }
/* Change the owner and/or group of the specified FILES. BIT_FLAGS specifies how to treat each symlink-to-directory that is encountered during a recursive traversal. CHOPT specifies additional options. If UID is not -1, then change the owner id of each file to UID. If GID is not -1, then change the group id of each file to GID. If REQUIRED_UID and/or REQUIRED_GID is not -1, then change only files with user ID and group ID that match the non-(-1) value(s). Return true if successful. */ extern bool chown_files (char **files, int bit_flags, uid_t uid, gid_t gid, uid_t required_uid, gid_t required_gid, struct Chown_option const *chopt) { bool ok = true; /* Use lstat and stat only if they're needed. */ int stat_flags = ((required_uid != (uid_t) -1 || required_gid != (gid_t) -1 || chopt->affect_symlink_referent || chopt->verbosity != V_off) ? 0 : FTS_NOSTAT); FTS *fts = xfts_open (files, bit_flags | stat_flags, NULL); while (1) { FTSENT *ent; ent = fts_read (fts); if (ent == NULL) { if (errno != 0) { /* FIXME: try to give a better message */ if (! chopt->force_silent) error (0, errno, _("fts_read failed")); ok = false; } break; } ok &= change_file_owner (fts, ent, uid, gid, required_uid, required_gid, chopt); } if (fts_close (fts) != 0) { error (0, errno, _("fts_close failed")); ok = false; } return ok; }
/* Change the owner and/or group of the specified FILES. BIT_FLAGS specifies how to treat each symlink-to-directory that is encountered during a recursive traversal. CHOPT specifies additional options. If UID is not -1, then change the owner id of each file to UID. If GID is not -1, then change the group id of each file to GID. If REQUIRED_UID and/or REQUIRED_GID is not -1, then change only files with user ID and group ID that match the non-(-1) value(s). Return true if successful. */ extern bool chown_files (char **files, int bit_flags, uid_t uid, gid_t gid, uid_t required_uid, gid_t required_gid, struct Chown_option const *chopt) { bool ok = true; /* Use lstat and stat only if they're needed. */ int stat_flags = ((required_uid != (uid_t) -1 || required_gid != (gid_t) -1 || chopt->affect_symlink_referent || chopt->verbosity != V_off) ? 0 : FTS_NOSTAT); FTS *fts = xfts_open (files, bit_flags | stat_flags, NULL); while (1) { FTSENT *ent; ent = fts_read (fts); if (ent == NULL) { if (errno != 0) { /* FIXME: try to give a better message */ error (0, errno, _("fts_read failed")); ok = false; } break; } ok &= change_file_owner (fts, ent, uid, gid, required_uid, required_gid, chopt); } /* Ignore failure, since the only way it can do so is in failing to return to the original directory, and since we're about to exit, that doesn't matter. */ fts_close (fts); return ok; }