fstool.c (7144B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; version 2 of the License. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 19 #ifdef HAVE_CONFIG_H 20 # include <config.h> 21 #endif 22 23 #include "fstool.h" 24 #include "util.h" 25 26 #include <lib/vserver.h> 27 28 #include <getopt.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <dirent.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 36 #define ENSC_WRAPPERS_DIRENT 1 37 #define ENSC_WRAPPERS_FCNTL 1 38 #define ENSC_WRAPPERS_UNISTD 1 39 #include <wrappers.h> 40 41 struct Arguments const * global_args = 0; 42 43 int wrapper_exit_code = 1; 44 45 inline static bool 46 isSpecialDir(char const *d) 47 { 48 return ( (d[0]=='.' && !global_args->do_display_dot) || 49 (d[0]=='.' && (d[1]=='\0' || (d[1]=='.' && d[2]=='\0'))) ); 50 } 51 52 #define CONCAT_PATHS(LHS, LHS_LEN, RHS) \ 53 size_t l_rhs = strlen(RHS); \ 54 char new_path[(LHS_LEN) + l_rhs + sizeof("/")]; \ 55 memcpy(new_path, LHS, (LHS_LEN)); \ 56 memcpy(new_path+(LHS_LEN), "/", 1); \ 57 memcpy(new_path+(LHS_LEN)+1, RHS, l_rhs); \ 58 new_path[(LHS_LEN)+1+l_rhs] = '\0'; 59 60 static uint64_t 61 iterateFilesystem(char const *path) 62 { 63 bool do_again = false; 64 size_t path_len = strlen(path); 65 uint64_t err = 0; 66 struct stat cur_st; 67 DIR * dir = opendir("."); 68 69 if (dir==0) { 70 perror("opendir()"); 71 return 1; 72 } 73 74 // show current directory entry first 75 if (lstat(".", &cur_st)==-1) perror("lstat()"); 76 else err += handleFile(".", path) ? 0 : 1; 77 78 // strip trailing '/' 79 while (path_len>0 && path[path_len-1]=='/') --path_len; 80 81 // process regular files before directories 82 for (;;) { 83 struct dirent *ent = Ereaddir(dir); 84 struct stat st; 85 86 if (ent==0) break; 87 if (isSpecialDir(ent->d_name)) continue; 88 89 if (lstat(ent->d_name, &st)==-1) { 90 perror("lstat()"); 91 ++err; 92 continue; 93 } 94 95 if (S_ISDIR(st.st_mode) && global_args->do_recurse) { 96 do_again = true; 97 continue; 98 } 99 100 { 101 CONCAT_PATHS(path, path_len, ent->d_name); 102 err += handleFile(ent->d_name, new_path) ? 0 : 1; 103 } 104 } 105 106 if (do_again) { 107 int cur_dir = Eopen(".", O_RDONLY, 0); 108 rewinddir(dir); 109 110 for (;;) { 111 struct dirent *ent = Ereaddir(dir); 112 struct stat st; 113 114 if (ent==0) break; 115 if (isSpecialDir(ent->d_name)) continue; 116 117 if (lstat(ent->d_name, &st)==-1) { 118 perror("lstat()"); 119 ++err; 120 continue; 121 } 122 123 if (!S_ISDIR(st.st_mode) || 124 (global_args->local_fs && st.st_dev!=cur_st.st_dev)) 125 continue; 126 127 if (safeChdir(ent->d_name, &st)==-1) { 128 perror("chdir()"); 129 ++err; 130 continue; 131 } 132 133 { 134 CONCAT_PATHS(path, path_len, ent->d_name); 135 err += iterateFilesystem(new_path); 136 } 137 Efchdir(cur_dir); 138 } 139 Eclose(cur_dir); 140 } 141 142 Eclosedir(dir); 143 144 return err; 145 } 146 #undef CONCAT_PATHS 147 148 static uint64_t 149 processFile(char const *path) 150 { 151 struct stat st; 152 153 if (lstat(path, &st)==-1) { 154 perror("lstat()"); 155 return 1; 156 } 157 158 if (S_ISDIR(st.st_mode) && !global_args->do_display_dir) { 159 int cur_dir = Eopen(".", O_RDONLY, 0); 160 uint64_t ret; 161 Echdir(path); 162 ret = iterateFilesystem(path); 163 Efchdir(cur_dir); 164 Eclose(cur_dir); 165 return ret; 166 } 167 else 168 return handleFile(path, path) ? 0 : 1; 169 } 170 171 int main(int argc, char *argv[]) 172 { 173 uint64_t err_cnt = 0; 174 int i; 175 struct Arguments args = { 176 .do_recurse = false, 177 .do_display_dot = false, 178 .do_display_dir = false, 179 .do_mapping = true, 180 .ctx = VC_NOCTX, 181 .is_legacy = false, 182 .do_set = false, 183 .do_unset = false, 184 .local_fs = false, 185 .set_mask = 0, 186 .del_mask = 0, 187 .no_unified = false, 188 }; 189 190 global_args = &args; 191 while (1) { 192 int c = getopt_long(argc, argv, CMDLINE_OPTIONS_SHORT, 193 CMDLINE_OPTIONS, 0); 194 long flags; 195 char *endptr; 196 if (c==-1) break; 197 198 switch (c) { 199 case CMD_HELP : showHelp(1, argv[0], 0); 200 case CMD_VERSION : showVersion(); 201 case CMD_IMMU : args.set_mask |= VC_IATTR_IMMUTABLE; /*@fallthrough@*/ 202 case CMD_IMMUX : args.set_mask |= VC_IATTR_IUNLINK; break; 203 case CMD_IMMUTABLE : args.set_mask |= VC_IATTR_IMMUTABLE; break; 204 case CMD_ADMIN : args.set_mask |= VC_IATTR_ADMIN; break; 205 case CMD_WATCH : args.set_mask |= VC_IATTR_WATCH; break; 206 case CMD_HIDE : args.set_mask |= VC_IATTR_HIDE; break; 207 case CMD_BARRIER : args.set_mask |= VC_IATTR_BARRIER; break; 208 case CMD_WRITE : args.set_mask |= VC_IATTR_WRITE; break; 209 case CMD_COW : args.set_mask |= VC_IATTR_COW; break; 210 case CMD_UNSET_IMMU : args.del_mask |= VC_IATTR_IMMUTABLE; /*@fallthrough@*/ 211 case CMD_UNSET_IMMUX : args.del_mask |= VC_IATTR_IUNLINK; break; 212 case CMD_UNSET_IMMUTABLE : args.del_mask |= VC_IATTR_IMMUTABLE; break; 213 case CMD_UNSET_ADMIN : args.del_mask |= VC_IATTR_ADMIN; break; 214 case CMD_UNSET_WATCH : args.del_mask |= VC_IATTR_WATCH; break; 215 case CMD_UNSET_HIDE : args.del_mask |= VC_IATTR_HIDE; break; 216 case CMD_UNSET_BARRIER : args.del_mask |= VC_IATTR_BARRIER; break; 217 case CMD_UNSET_WRITE : args.del_mask |= VC_IATTR_WRITE; break; 218 case CMD_UNSET_COW : args.del_mask |= VC_IATTR_COW; break; 219 case CMD_FLAGS : 220 case CMD_UNSET_FLAGS : 221 flags = strtoul(optarg, &endptr, 0); 222 if ((flags == 0 && errno != 0) || *endptr != '\0') { 223 WRITE_MSG(2, "Invalid flags argument: '"); 224 WRITE_STR(2, optarg); 225 WRITE_MSG(2, "'; try '--help' for more information\n"); 226 return EXIT_FAILURE; 227 } 228 if (c == CMD_FLAGS) 229 args.set_mask |= flags; 230 else 231 args.del_mask |= flags; 232 break; 233 case 'R' : args.do_recurse = true; break; 234 case 'a' : args.do_display_dot = true; break; 235 case 'd' : args.do_display_dir = true; break; 236 case 'n' : args.do_mapping = false; break; 237 case 's' : args.do_set = true; break; 238 case 'u' : args.do_unset = true; break; 239 case 'c' : args.ctx_str = optarg; break; 240 case 'x' : args.local_fs = true; break; 241 case 'U' : args.no_unified = true; break; 242 default : 243 WRITE_MSG(2, "Try '"); 244 WRITE_STR(2, argv[0]); 245 WRITE_MSG(2, " --help' for more information.\n"); 246 return EXIT_FAILURE; 247 break; 248 } 249 } 250 251 fixupParams(&args, argc); 252 253 if (optind==argc) 254 err_cnt = processFile("."); 255 else for (i=optind; i<argc; ++i) 256 err_cnt += processFile(argv[i]); 257 258 return err_cnt>0 ? EXIT_FAILURE : EXIT_SUCCESS; 259 }