chattr.c 4.5 KB

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