busybox/e2fsprogs/chattr.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * chattr.c             - Change file attributes on an ext2 file system
   4 *
   5 * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
   6 *                           Laboratoire MASI, Institut Blaise Pascal
   7 *                           Universite Pierre et Marie Curie (Paris VI)
   8 *
   9 * This file can be redistributed under the terms of the GNU General
  10 * Public License
  11 */
  12
  13/*
  14 * History:
  15 * 93/10/30     - Creation
  16 * 93/11/13     - Replace stat() calls by lstat() to avoid loops
  17 * 94/02/27     - Integrated in Ted's distribution
  18 * 98/12/29     - Ignore symlinks when working recursively (G M Sipe)
  19 * 98/12/29     - Display version info only when -V specified (G M Sipe)
  20 */
  21
  22#include "libbb.h"
  23#include "e2fs_lib.h"
  24
  25#define OPT_ADD 1
  26#define OPT_REM 2
  27#define OPT_SET 4
  28#define OPT_SET_VER 8
  29
  30struct globals {
  31        unsigned long version;
  32        unsigned long af;
  33        unsigned long rf;
  34        smallint flags;
  35        smallint recursive;
  36};
  37
  38static unsigned long get_flag(char c)
  39{
  40        const char *fp = strchr(e2attr_flags_sname_chattr, c);
  41        if (fp)
  42                return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr];
  43        bb_show_usage();
  44}
  45
  46static int decode_arg(const char *arg, struct globals *gp)
  47{
  48        unsigned long *fl;
  49        char opt = *arg++;
  50
  51        fl = &gp->af;
  52        if (opt == '-') {
  53                gp->flags |= OPT_REM;
  54                fl = &gp->rf;
  55        } else if (opt == '+') {
  56                gp->flags |= OPT_ADD;
  57        } else if (opt == '=') {
  58                gp->flags |= OPT_SET;
  59        } else
  60                return 0;
  61
  62        while (*arg)
  63                *fl |= get_flag(*arg++);
  64
  65        return 1;
  66}
  67
  68static void change_attributes(const char *name, struct globals *gp);
  69
  70static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
  71{
  72        char *path = concat_subpath_file(dir_name, de->d_name);
  73        /* path is NULL if de->d_name is "." or "..", else... */
  74        if (path) {
  75                change_attributes(path, gp);
  76                free(path);
  77        }
  78        return 0;
  79}
  80
  81static void change_attributes(const char *name, struct globals *gp)
  82{
  83        unsigned long fsflags;
  84        struct stat st;
  85
  86        if (lstat(name, &st) != 0) {
  87                bb_perror_msg("stat %s", name);
  88                return;
  89        }
  90        if (S_ISLNK(st.st_mode) && gp->recursive)
  91                return;
  92
  93        /* Don't try to open device files, fifos etc.  We probably
  94         * ought to display an error if the file was explicitly given
  95         * on the command line (whether or not recursive was
  96         * requested).  */
  97        if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
  98                return;
  99
 100        if (gp->flags & OPT_SET_VER)
 101                if (fsetversion(name, gp->version) != 0)
 102                        bb_perror_msg("setting version on %s", name);
 103
 104        if (gp->flags & OPT_SET) {
 105                fsflags = gp->af;
 106        } else {
 107                if (fgetflags(name, &fsflags) != 0) {
 108                        bb_perror_msg("reading flags on %s", name);
 109                        goto skip_setflags;
 110                }
 111                /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */
 112                        fsflags &= ~gp->rf;
 113                /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
 114                        fsflags |= gp->af;
 115                /* What is this? And why it's not done for SET case? */
 116                if (!S_ISDIR(st.st_mode))
 117                        fsflags &= ~EXT2_DIRSYNC_FL;
 118        }
 119        if (fsetflags(name, fsflags) != 0)
 120                bb_perror_msg("setting flags on %s", name);
 121
 122 skip_setflags:
 123        if (gp->recursive && S_ISDIR(st.st_mode))
 124                iterate_on_dir(name, chattr_dir_proc, gp);
 125}
 126
 127int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 128int chattr_main(int argc UNUSED_PARAM, char **argv)
 129{
 130        struct globals g;
 131        char *arg;
 132
 133        memset(&g, 0, sizeof(g));
 134
 135        /* parse the args */
 136        while ((arg = *++argv)) {
 137                /* take care of -R and -v <version> */
 138                if (arg[0] == '-'
 139                 && (arg[1] == 'R' || arg[1] == 'v')
 140                 && !arg[2]
 141                ) {
 142                        if (arg[1] == 'R') {
 143                                g.recursive = 1;
 144                                continue;
 145                        }
 146                        /* arg[1] == 'v' */
 147                        if (!*++argv)
 148                                bb_show_usage();
 149                        g.version = xatoul(*argv);
 150                        g.flags |= OPT_SET_VER;
 151                        continue;
 152                }
 153
 154                if (!decode_arg(arg, &g))
 155                        break;
 156        }
 157
 158        /* run sanity checks on all the arguments given us */
 159        if (!*argv)
 160                bb_show_usage();
 161        if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
 162                bb_error_msg_and_die("= is incompatible with - and +");
 163        if (g.rf & g.af)
 164                bb_error_msg_and_die("can't set and unset a flag");
 165        if (!g.flags)
 166                bb_error_msg_and_die("must use '-v', =, - or +");
 167
 168        /* now run chattr on all the files passed to us */
 169        do change_attributes(*argv, &g); while (*++argv);
 170
 171        return EXIT_SUCCESS;
 172}
 173