chattr.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. //config:config CHATTR
  13. //config: bool "chattr"
  14. //config: default y
  15. //config: help
  16. //config: chattr changes the file attributes on a second extended file system.
  17. //applet:IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP))
  18. //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
  19. //usage:#define chattr_trivial_usage
  20. //usage: "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..."
  21. //usage:#define chattr_full_usage "\n\n"
  22. //usage: "Change ext2 file attributes\n"
  23. //usage: "\nModifiers:"
  24. //usage: "\n -,+,= Remove/add/set attributes"
  25. //usage: "\nAttributes:"
  26. //usage: "\n A Don't track atime"
  27. //usage: "\n a Append mode only"
  28. //usage: "\n c Enable compress"
  29. //usage: "\n D Write dir contents synchronously"
  30. //usage: "\n d Don't backup with dump"
  31. //usage: "\n i Cannot be modified (immutable)"
  32. //usage: "\n j Write all data to journal first"
  33. //usage: "\n s Zero disk storage when deleted"
  34. //usage: "\n S Write synchronously"
  35. //usage: "\n t Disable tail-merging of partial blocks with other files"
  36. //usage: "\n u Allow file to be undeleted"
  37. //usage: "\n -R Recurse"
  38. //usage: "\n -v VER Set version/generation number"
  39. #include "libbb.h"
  40. #include "e2fs_lib.h"
  41. #define OPT_ADD 1
  42. #define OPT_REM 2
  43. #define OPT_SET 4
  44. #define OPT_SET_VER 8
  45. struct globals {
  46. unsigned long version;
  47. unsigned long af;
  48. unsigned long rf;
  49. smallint flags;
  50. smallint recursive;
  51. };
  52. static unsigned long get_flag(char c)
  53. {
  54. const char *fp = strchr(e2attr_flags_sname_chattr, c);
  55. if (fp)
  56. return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr];
  57. bb_show_usage();
  58. }
  59. static int decode_arg(const char *arg, struct globals *gp)
  60. {
  61. unsigned long *fl;
  62. char opt = *arg++;
  63. fl = &gp->af;
  64. if (opt == '-') {
  65. gp->flags |= OPT_REM;
  66. fl = &gp->rf;
  67. } else if (opt == '+') {
  68. gp->flags |= OPT_ADD;
  69. } else if (opt == '=') {
  70. gp->flags |= OPT_SET;
  71. } else
  72. return 0;
  73. while (*arg)
  74. *fl |= get_flag(*arg++);
  75. return 1;
  76. }
  77. static void change_attributes(const char *name, struct globals *gp);
  78. static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
  79. {
  80. char *path = concat_subpath_file(dir_name, de->d_name);
  81. /* path is NULL if de->d_name is "." or "..", else... */
  82. if (path) {
  83. change_attributes(path, gp);
  84. free(path);
  85. }
  86. return 0;
  87. }
  88. static void change_attributes(const char *name, struct globals *gp)
  89. {
  90. unsigned long fsflags;
  91. struct stat st;
  92. if (lstat(name, &st) != 0) {
  93. bb_perror_msg("stat %s", name);
  94. return;
  95. }
  96. if (S_ISLNK(st.st_mode) && gp->recursive)
  97. return;
  98. /* Don't try to open device files, fifos etc. We probably
  99. * ought to display an error if the file was explicitly given
  100. * on the command line (whether or not recursive was
  101. * requested). */
  102. if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
  103. return;
  104. if (gp->flags & OPT_SET_VER)
  105. if (fsetversion(name, gp->version) != 0)
  106. bb_perror_msg("setting version on %s", name);
  107. if (gp->flags & OPT_SET) {
  108. fsflags = gp->af;
  109. } else {
  110. if (fgetflags(name, &fsflags) != 0) {
  111. bb_perror_msg("reading flags on %s", name);
  112. goto skip_setflags;
  113. }
  114. /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */
  115. fsflags &= ~gp->rf;
  116. /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
  117. fsflags |= gp->af;
  118. /* What is this? And why it's not done for SET case? */
  119. if (!S_ISDIR(st.st_mode))
  120. fsflags &= ~EXT2_DIRSYNC_FL;
  121. }
  122. if (fsetflags(name, fsflags) != 0)
  123. bb_perror_msg("setting flags on %s", name);
  124. skip_setflags:
  125. if (gp->recursive && S_ISDIR(st.st_mode))
  126. iterate_on_dir(name, chattr_dir_proc, gp);
  127. }
  128. int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  129. int chattr_main(int argc UNUSED_PARAM, char **argv)
  130. {
  131. struct globals g;
  132. char *arg;
  133. memset(&g, 0, sizeof(g));
  134. /* parse the args */
  135. while ((arg = *++argv)) {
  136. /* take care of -R and -v <version> */
  137. if (arg[0] == '-'
  138. && (arg[1] == 'R' || arg[1] == 'v')
  139. && !arg[2]
  140. ) {
  141. if (arg[1] == 'R') {
  142. g.recursive = 1;
  143. continue;
  144. }
  145. /* arg[1] == 'v' */
  146. if (!*++argv)
  147. bb_show_usage();
  148. g.version = xatoul(*argv);
  149. g.flags |= OPT_SET_VER;
  150. continue;
  151. }
  152. if (!decode_arg(arg, &g))
  153. break;
  154. }
  155. /* run sanity checks on all the arguments given us */
  156. if (!*argv)
  157. bb_show_usage();
  158. if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
  159. bb_error_msg_and_die("= is incompatible with - and +");
  160. if (g.rf & g.af)
  161. bb_error_msg_and_die("can't set and unset a flag");
  162. if (!g.flags)
  163. bb_error_msg_and_die("must use '-v', =, - or +");
  164. /* now run chattr on all the files passed to us */
  165. do change_attributes(*argv, &g); while (*++argv);
  166. return EXIT_SUCCESS;
  167. }