chattr.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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 "busybox.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. static int flags;
  27. static int recursive;
  28. static unsigned long version;
  29. static unsigned long af;
  30. static unsigned long rf;
  31. static unsigned long sf;
  32. struct flags_char {
  33. unsigned long flag;
  34. char optchar;
  35. };
  36. static const struct flags_char flags_array[] = {
  37. { EXT2_NOATIME_FL, 'A' },
  38. { EXT2_SYNC_FL, 'S' },
  39. { EXT2_DIRSYNC_FL, 'D' },
  40. { EXT2_APPEND_FL, 'a' },
  41. { EXT2_COMPR_FL, 'c' },
  42. { EXT2_NODUMP_FL, 'd' },
  43. { EXT2_IMMUTABLE_FL, 'i' },
  44. { EXT3_JOURNAL_DATA_FL, 'j' },
  45. { EXT2_SECRM_FL, 's' },
  46. { EXT2_UNRM_FL, 'u' },
  47. { EXT2_NOTAIL_FL, 't' },
  48. { EXT2_TOPDIR_FL, 'T' },
  49. { 0, 0 }
  50. };
  51. static unsigned long get_flag(char c)
  52. {
  53. const struct flags_char *fp;
  54. for (fp = flags_array; fp->optchar; fp++)
  55. if (fp->optchar == c)
  56. return fp->flag;
  57. bb_show_usage();
  58. }
  59. static int decode_arg(const char *arg)
  60. {
  61. unsigned long *fl;
  62. char opt = *arg++;
  63. if (opt == '-') {
  64. flags |= OPT_REM;
  65. fl = &rf;
  66. } else if (opt == '+') {
  67. flags |= OPT_ADD;
  68. fl = &af;
  69. } else if (opt == '=') {
  70. flags |= OPT_SET;
  71. fl = &sf;
  72. } else
  73. return 0;
  74. while (*arg)
  75. *fl |= get_flag(*arg++);
  76. return 1;
  77. }
  78. static void change_attributes(const char *name);
  79. static int chattr_dir_proc(const char *dir_name, struct dirent *de,
  80. void *private ATTRIBUTE_UNUSED)
  81. {
  82. char *path = concat_subpath_file(dir_name, de->d_name);
  83. /* path is NULL if de->d_name is "." or "..", else... */
  84. if (path) {
  85. change_attributes(path);
  86. free(path);
  87. }
  88. return 0;
  89. }
  90. static void change_attributes(const char *name)
  91. {
  92. unsigned long fsflags;
  93. struct stat st;
  94. if (lstat(name, &st) == -1) {
  95. bb_perror_msg("stat %s", name);
  96. return;
  97. }
  98. if (S_ISLNK(st.st_mode) && recursive)
  99. return;
  100. /* Don't try to open device files, fifos etc. We probably
  101. * ought to display an error if the file was explicitly given
  102. * on the command line (whether or not recursive was
  103. * requested). */
  104. if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
  105. return;
  106. if (flags & OPT_SET_VER)
  107. if (fsetversion(name, version) == -1)
  108. bb_perror_msg("setting version on %s", name);
  109. if (flags & OPT_SET) {
  110. fsflags = sf;
  111. } else {
  112. if (fgetflags(name, &fsflags) == -1) {
  113. bb_perror_msg("reading flags on %s", name);
  114. goto skip_setflags;
  115. }
  116. if (flags & OPT_REM)
  117. fsflags &= ~rf;
  118. if (flags & OPT_ADD)
  119. fsflags |= af;
  120. if (!S_ISDIR(st.st_mode))
  121. fsflags &= ~EXT2_DIRSYNC_FL;
  122. }
  123. if (fsetflags(name, fsflags) == -1)
  124. bb_perror_msg("setting flags on %s", name);
  125. skip_setflags:
  126. if (recursive && S_ISDIR(st.st_mode))
  127. iterate_on_dir(name, chattr_dir_proc, NULL);
  128. }
  129. int chattr_main(int argc, char **argv)
  130. {
  131. char *arg;
  132. /* parse the args */
  133. while ((arg = *++argv)) {
  134. /* take care of -R and -v <version> */
  135. if (arg[0] == '-') {
  136. if (arg[1] == 'R' && arg[2] == '\0') {
  137. recursive = 1;
  138. continue;
  139. }
  140. if (arg[1] == 'v' && arg[2] == '\0') {
  141. if (!*++argv)
  142. bb_show_usage();
  143. version = xatoul(*argv);
  144. flags |= OPT_SET_VER;
  145. continue;
  146. }
  147. }
  148. if (!decode_arg(arg))
  149. break;
  150. }
  151. /* run sanity checks on all the arguments given us */
  152. if (!*argv)
  153. bb_show_usage();
  154. if ((flags & OPT_SET) && (flags & (OPT_ADD|OPT_REM)))
  155. bb_error_msg_and_die("= is incompatible with - and +");
  156. if (rf & af)
  157. bb_error_msg_and_die("can't set and unset a flag");
  158. if (!flags)
  159. bb_error_msg_and_die("must use '-v', =, - or +");
  160. /* now run chattr on all the files passed to us */
  161. do change_attributes(*argv); while (*++argv);
  162. return EXIT_SUCCESS;
  163. }