chattr.c 4.1 KB

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