aboutsummaryrefslogtreecommitdiffstats
path: root/src/fcopy
diff options
context:
space:
mode:
authorLibravatar startx2017 <vradu.startx@yandex.com>2017-04-10 09:24:00 -0400
committerLibravatar startx2017 <vradu.startx@yandex.com>2017-04-10 09:24:00 -0400
commitb05f7f3bd9d0264a6e143e10269e3eca5416b048 (patch)
treec14f7114ddfd89fcaa32a3ed458e150131cd07de /src/fcopy
parentDoc update for baloo_file profile (diff)
downloadfirejail-b05f7f3bd9d0264a6e143e10269e3eca5416b048.tar.gz
firejail-b05f7f3bd9d0264a6e143e10269e3eca5416b048.tar.zst
firejail-b05f7f3bd9d0264a6e143e10269e3eca5416b048.zip
--quiet fixes
Diffstat (limited to 'src/fcopy')
-rw-r--r--src/fcopy/main.c577
1 files changed, 296 insertions, 281 deletions
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index 9f19b6dd8..88379001c 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -16,16 +16,16 @@
16 * You should have received a copy of the GNU General Public License along 16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc., 17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/ 19 */
20 20
21#include "../include/common.h" 21#include "../include/common.h"
22#include <fcntl.h> 22#include <fcntl.h>
23#include <ftw.h> 23#include <ftw.h>
24#include <errno.h> 24#include <errno.h>
25 25
26int arg_quiet = 0;
26static int arg_follow_link = 0; 27static int arg_follow_link = 0;
27 28
28
29#define COPY_LIMIT (500 * 1024 *1024) 29#define COPY_LIMIT (500 * 1024 *1024)
30static int size_limit_reached = 0; 30static int size_limit_reached = 0;
31static unsigned file_cnt = 0; 31static unsigned file_cnt = 0;
@@ -34,323 +34,338 @@ static unsigned size_cnt = 0;
34static char *outpath = NULL; 34static char *outpath = NULL;
35static char *inpath = NULL; 35static char *inpath = NULL;
36 36
37
38// modified version of the function from util.c 37// modified version of the function from util.c
39static void copy_file(const char *srcname, const char *destname, mode_t mode, uid_t uid, gid_t gid) { 38static void copy_file(const char *srcname, const char *destname, mode_t mode, uid_t uid, gid_t gid) {
40 assert(srcname); 39 assert(srcname);
41 assert(destname); 40 assert(destname);
42 mode &= 07777; 41 mode &= 07777;
43 42
44 // open source 43 // open source
45 int src = open(srcname, O_RDONLY); 44 int src = open(srcname, O_RDONLY);
46 if (src < 0) { 45 if (src < 0) {
47 fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", srcname); 46 if (!arg_quiet)
48 return; 47 fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", srcname);
49 } 48 return;
50 49 }
51 // open destination 50
52 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, 0755); 51 // open destination
53 if (dst < 0) { 52 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, 0755);
54 fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname); 53 if (dst < 0) {
55 close(src); 54 if (!arg_quiet)
56 return; 55 fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname);
57 } 56 close(src);
58 57 return;
59 // copy 58 }
60 ssize_t len; 59
61 static const int BUFLEN = 1024; 60 // copy
62 unsigned char buf[BUFLEN]; 61 ssize_t len;
63 while ((len = read(src, buf, BUFLEN)) > 0) { 62 static const int BUFLEN = 1024;
64 int done = 0; 63 unsigned char buf[BUFLEN];
65 while (done != len) { 64 while ((len = read(src, buf, BUFLEN)) > 0) {
66 int rv = write(dst, buf + done, len - done); 65 int done = 0;
67 if (rv == -1) 66 while (done != len) {
68 goto errexit; 67 int rv = write(dst, buf + done, len - done);
69 done += rv; 68 if (rv == -1)
70 } 69 goto errexit;
71 } 70 done += rv;
72 fflush(0); 71 }
73 72 }
74 if (fchown(dst, uid, gid) == -1) 73 fflush(0);
75 goto errexit; 74
76 if (fchmod(dst, mode) == -1) 75 if (fchown(dst, uid, gid) == -1)
77 goto errexit; 76 goto errexit;
78 77 if (fchmod(dst, mode) == -1)
79 close(src); 78 goto errexit;
80 close(dst); 79
81 80 close(src);
82 return; 81 close(dst);
82
83 return;
83 84
84errexit: 85errexit:
85 close(src); 86 close(src);
86 close(dst); 87 close(dst);
87 unlink(destname); 88 unlink(destname);
88 fprintf(stderr, "Warning fcopy: cannot copy %s\n", destname); 89 if (!arg_quiet)
90 fprintf(stderr, "Warning fcopy: cannot copy %s\n", destname);
89} 91}
90 92
91 93
92
93// modified version of the function in firejail/util.c 94// modified version of the function in firejail/util.c
94static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { 95static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) {
95 assert(fname); 96 assert(fname);
96 mode &= 07777; 97 mode &= 07777;
97 98
98 if (mkdir(fname, mode) == -1 || 99 if (mkdir(fname, mode) == -1 ||
99 chmod(fname, mode) == -1) { 100 chmod(fname, mode) == -1) {
100 fprintf(stderr, "Error fcopy: failed to create %s directory\n", fname); 101 fprintf(stderr, "Error fcopy: failed to create %s directory\n", fname);
101 errExit("mkdir/chmod"); 102 errExit("mkdir/chmod");
102 } 103 }
103 if (chown(fname, uid, gid)) 104 if (chown(fname, uid, gid)) {
104 fprintf(stderr, "Warning fcopy: failed to change ownership of %s\n", fname); 105 if (!arg_quiet)
106 fprintf(stderr, "Warning fcopy: failed to change ownership of %s\n", fname);
107 }
105} 108}
106 109
110
107void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { 111void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) {
108 (void) mode; 112 (void) mode;
109 (void) uid; 113 (void) uid;
110 (void) gid; 114 (void) gid;
111 char *rp = realpath(target, NULL); 115 char *rp = realpath(target, NULL);
112 if (rp) { 116 if (rp) {
113 if (symlink(rp, linkpath) == -1) 117 if (symlink(rp, linkpath) == -1)
114 goto errout; 118 goto errout;
115 free(rp); 119 free(rp);
116 } 120 }
117 else 121 else
118 goto errout; 122 goto errout;
119 123
120 return; 124 return;
121errout: 125errout:
122 fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target); 126 if (!arg_quiet)
127 fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target);
123} 128}
124 129
130
125static int first = 1; 131static int first = 1;
126static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) { 132static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) {
127 (void) st; 133 (void) st;
128 (void) sftw; 134 (void) sftw;
129 assert(infname); 135 assert(infname);
130 assert(*infname != '\0'); 136 assert(*infname != '\0');
131 assert(outpath); 137 assert(outpath);
132 assert(*outpath != '\0'); 138 assert(*outpath != '\0');
133 assert(inpath); 139 assert(inpath);
134 140
135 // check size limit 141 // check size limit
136 if (size_limit_reached) 142 if (size_limit_reached)
137 return 0; 143 return 0;
138 144
139 145 char *outfname;
140 char *outfname; 146 if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1)
141 if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1) 147 errExit("asprintf");
142 errExit("asprintf"); 148
143 149 // don't copy it if we already have the file
144 // don't copy it if we already have the file 150 struct stat s;
145 struct stat s; 151 if (stat(outfname, &s) == 0) {
146 if (stat(outfname, &s) == 0) { 152 if (first)
147 if (first) 153 first = 0;
148 first = 0; 154 else if (!arg_quiet)
149 else 155 fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname);
150 fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); 156 free(outfname);
151 free(outfname); 157 return 0;
152 return 0; 158 }
153 } 159
154 160 // extract mode and ownership
155 // extract mode and ownership 161 if (stat(infname, &s) != 0) {
156 if (stat(infname, &s) != 0) { 162 if (!arg_quiet)
157 fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); 163 fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname);
158 free(outfname); 164 free(outfname);
159 return 0; 165 return 0;
160 } 166 }
161 uid_t uid = s.st_uid; 167 uid_t uid = s.st_uid;
162 gid_t gid = s.st_gid; 168 gid_t gid = s.st_gid;
163 mode_t mode = s.st_mode; 169 mode_t mode = s.st_mode;
164 170
165 // recalculate size 171 // recalculate size
166 if ((s.st_size + size_cnt) > COPY_LIMIT) { 172 if ((s.st_size + size_cnt) > COPY_LIMIT) {
167 fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024); 173 fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024);
168 size_limit_reached = 1; 174 size_limit_reached = 1;
169 free(outfname); 175 free(outfname);
170 return 0; 176 return 0;
171 } 177 }
172 178
173 file_cnt++; 179 file_cnt++;
174 size_cnt += s.st_size; 180 size_cnt += s.st_size;
175 181
176 if(ftype == FTW_F) { 182 if(ftype == FTW_F) {
177 copy_file(infname, outfname, mode, uid, gid); 183 copy_file(infname, outfname, mode, uid, gid);
178 } 184 }
179 else if (ftype == FTW_D) { 185 else if (ftype == FTW_D) {
180 mkdir_attr(outfname, mode, uid, gid); 186 mkdir_attr(outfname, mode, uid, gid);
181 } 187 }
182 else if (ftype == FTW_SL) { 188 else if (ftype == FTW_SL) {
183 copy_link(infname, outfname, mode, uid, gid); 189 copy_link(infname, outfname, mode, uid, gid);
184 } 190 }
185 191
186 return(0); 192 return(0);
187} 193}
188 194
195
189static char *check(const char *src) { 196static char *check(const char *src) {
190 struct stat s; 197 struct stat s;
191 char *rsrc = realpath(src, NULL); 198 char *rsrc = realpath(src, NULL);
192 if (!rsrc || stat(rsrc, &s) == -1) 199 if (!rsrc || stat(rsrc, &s) == -1)
193 goto errexit; 200 goto errexit;
194 201
195 // check uid 202 // check uid
196 if (s.st_uid != getuid() || s.st_gid != getgid()) 203 if (s.st_uid != getuid() || s.st_gid != getgid())
197 goto errexit; 204 goto errexit;
198 205
199 // dir, link, regular file 206 // dir, link, regular file
200 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode)) 207 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode))
201 return rsrc; // normal exit from the function 208 return rsrc; // normal exit from the function
202 209
203errexit: 210errexit:
204 fprintf(stderr, "Error fcopy: invalid file %s\n", src); 211 fprintf(stderr, "Error fcopy: invalid file %s\n", src);
205 exit(1); 212 exit(1);
206} 213}
207 214
215
208static void duplicate_dir(const char *src, const char *dest, struct stat *s) { 216static void duplicate_dir(const char *src, const char *dest, struct stat *s) {
209 (void) s; 217 (void) s;
210 char *rsrc = check(src); 218 char *rsrc = check(src);
211 char *rdest = check(dest); 219 char *rdest = check(dest);
212 inpath = rsrc; 220 inpath = rsrc;
213 outpath = rdest; 221 outpath = rdest;
214 222
215 // walk 223 // walk
216 if(nftw(rsrc, fs_copydir, 1, FTW_PHYS) != 0) { 224 if(nftw(rsrc, fs_copydir, 1, FTW_PHYS) != 0) {
217 fprintf(stderr, "Error: unable to copy file\n"); 225 fprintf(stderr, "Error: unable to copy file\n");
218 exit(1); 226 exit(1);
219 } 227 }
220 228
221 free(rsrc); 229 free(rsrc);
222 free(rdest); 230 free(rdest);
223} 231}
224 232
233
225static void duplicate_file(const char *src, const char *dest, struct stat *s) { 234static void duplicate_file(const char *src, const char *dest, struct stat *s) {
226 char *rsrc = check(src); 235 char *rsrc = check(src);
227 char *rdest = check(dest); 236 char *rdest = check(dest);
228 uid_t uid = s->st_uid; 237 uid_t uid = s->st_uid;
229 gid_t gid = s->st_gid; 238 gid_t gid = s->st_gid;
230 mode_t mode = s->st_mode; 239 mode_t mode = s->st_mode;
231 240
232 // build destination file name 241 // build destination file name
233 char *name; 242 char *name;
234 char *ptr = (arg_follow_link)? strrchr(src, '/'): strrchr(rsrc, '/'); 243 char *ptr = (arg_follow_link)? strrchr(src, '/'): strrchr(rsrc, '/');
235 ptr++; 244 ptr++;
236 if (asprintf(&name, "%s/%s", rdest, ptr) == -1) 245 if (asprintf(&name, "%s/%s", rdest, ptr) == -1)
237 errExit("asprintf"); 246 errExit("asprintf");
238 247
239 // copy 248 // copy
240 copy_file(rsrc, name, mode, uid, gid); 249 copy_file(rsrc, name, mode, uid, gid);
241 250
242 free(name); 251 free(name);
243 free(rsrc); 252 free(rsrc);
244 free(rdest); 253 free(rdest);
245} 254}
246 255
256
247static void duplicate_link(const char *src, const char *dest, struct stat *s) { 257static void duplicate_link(const char *src, const char *dest, struct stat *s) {
248 char *rsrc = check(src); // we drop the result and use the original name 258 char *rsrc = check(src); // we drop the result and use the original name
249 char *rdest = check(dest); 259 char *rdest = check(dest);
250 uid_t uid = s->st_uid; 260 uid_t uid = s->st_uid;
251 gid_t gid = s->st_gid; 261 gid_t gid = s->st_gid;
252 mode_t mode = s->st_mode; 262 mode_t mode = s->st_mode;
253 263
254 // build destination file name 264 // build destination file name
255 char *name; 265 char *name;
256// char *ptr = strrchr(rsrc, '/'); 266 // char *ptr = strrchr(rsrc, '/');
257 char *ptr = strrchr(src, '/'); 267 char *ptr = strrchr(src, '/');
258 ptr++; 268 ptr++;
259 if (asprintf(&name, "%s/%s", rdest, ptr) == -1) 269 if (asprintf(&name, "%s/%s", rdest, ptr) == -1)
260 errExit("asprintf"); 270 errExit("asprintf");
261 271
262 // copy 272 // copy
263 copy_link(rsrc, name, mode, uid, gid); 273 copy_link(rsrc, name, mode, uid, gid);
264 274
265 free(name); 275 free(name);
266 free(rsrc); 276 free(rsrc);
267 free(rdest); 277 free(rdest);
268} 278}
269 279
280
270static void usage(void) { 281static void usage(void) {
271 fputs("Usage: fcopy [--follow-link] src dest\n" 282 fputs("Usage: fcopy [--follow-link] src dest\n"
272 "\n" 283 "\n"
273 "Copy SRC to DEST/SRC. SRC may be a file, directory, or symbolic link.\n" 284 "Copy SRC to DEST/SRC. SRC may be a file, directory, or symbolic link.\n"
274 "If SRC is a directory it is copied recursively. If it is a symlink,\n" 285 "If SRC is a directory it is copied recursively. If it is a symlink,\n"
275 "the link itself is duplicated, unless --follow-link is given,\n" 286 "the link itself is duplicated, unless --follow-link is given,\n"
276 "in which case the destination of the link is copied.\n" 287 "in which case the destination of the link is copied.\n"
277 "DEST must already exist and must be a directory.\n", stderr); 288 "DEST must already exist and must be a directory.\n", stderr);
278} 289}
279 290
291
280int main(int argc, char **argv) { 292int main(int argc, char **argv) {
281#if 0 293#if 0
282{ 294 {
283//system("cat /proc/self/status"); 295 //system("cat /proc/self/status");
284int i; 296 int i;
285for (i = 0; i < argc; i++) 297 for (i = 0; i < argc; i++)
286 printf("*%s* ", argv[i]); 298 printf("*%s* ", argv[i]);
287printf("\n"); 299 printf("\n");
288} 300 }
289#endif 301#endif
290 char *src; 302 char *quiet = getenv("FIREJAIL_QUIET");
291 char *dest; 303 if (quiet && strcmp(quiet, "yes") == 0)
292 304 arg_quiet = 1;
293 if (argc == 3) { 305
294 src = argv[1]; 306 char *src;
295 dest = argv[2]; 307 char *dest;
296 arg_follow_link = 0; 308
297 } 309 if (argc == 3) {
298 else if (argc == 4 && !strcmp(argv[1], "--follow-link")) { 310 src = argv[1];
299 src = argv[2]; 311 dest = argv[2];
300 dest = argv[3]; 312 arg_follow_link = 0;
301 arg_follow_link = 1; 313 }
302 } 314 else if (argc == 4 && !strcmp(argv[1], "--follow-link")) {
303 else { 315 src = argv[2];
304 fprintf(stderr, "Error: arguments missing\n"); 316 dest = argv[3];
305 usage(); 317 arg_follow_link = 1;
306 exit(1); 318 }
307 } 319 else {
308 320 fprintf(stderr, "Error: arguments missing\n");
309 // check the two files; remove ending / 321 usage();
310 int len = strlen(src); 322 exit(1);
311 if (src[len - 1] == '/') 323 }
312 src[len - 1] = '\0'; 324
313 if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != (size_t)len) { 325 // check the two files; remove ending /
314 fprintf(stderr, "Error fcopy: invalid source file name %s\n", src); 326 int len = strlen(src);
315 exit(1); 327 if (src[len - 1] == '/')
316 } 328 src[len - 1] = '\0';
317 329 if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != (size_t)len) {
318 len = strlen(dest); 330 fprintf(stderr, "Error fcopy: invalid source file name %s\n", src);
319 if (dest[len - 1] == '/') 331 exit(1);
320 dest[len - 1] = '\0'; 332 }
321 if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != (size_t)len) { 333
322 fprintf(stderr, "Error fcopy: invalid dest file name %s\n", dest); 334 len = strlen(dest);
323 exit(1); 335 if (dest[len - 1] == '/')
324 } 336 dest[len - 1] = '\0';
325 337 if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != (size_t)len) {
326 338 fprintf(stderr, "Error fcopy: invalid dest file name %s\n", dest);
327 // the destination should be a directory; 339 exit(1);
328 struct stat s; 340 }
329 if (stat(dest, &s) == -1) { 341
330 fprintf(stderr, "Error fcopy: dest dir %s: %s\n", dest, strerror(errno)); 342 // the destination should be a directory;
331 exit(1); 343 struct stat s;
332 } 344 if (stat(dest, &s) == -1) {
333 if (!S_ISDIR(s.st_mode)) { 345 fprintf(stderr, "Error fcopy: dest dir %s: %s\n", dest, strerror(errno));
334 fprintf(stderr, "Error fcopy: dest %s is not a directory\n", dest); 346 exit(1);
335 exit(1); 347 }
336 } 348 if (!S_ISDIR(s.st_mode)) {
337 349 fprintf(stderr, "Error fcopy: dest %s is not a directory\n", dest);
338 // copy files 350 exit(1);
339 if ((arg_follow_link ? stat : lstat)(src, &s) == -1) { 351 }
340 fprintf(stderr, "Error fcopy: src %s: %s\n", src, strerror(errno)); 352
341 exit(1); 353 // copy files
342 } 354 if ((arg_follow_link ? stat : lstat)(src, &s) == -1) {
343 355 fprintf(stderr, "Error fcopy: src %s: %s\n", src, strerror(errno));
344 if (S_ISDIR(s.st_mode)) 356 exit(1);
345 duplicate_dir(src, dest, &s); 357 }
346 else if (S_ISREG(s.st_mode)) 358
347 duplicate_file(src, dest, &s); 359 if (S_ISDIR(s.st_mode))
348 else if (S_ISLNK(s.st_mode)) 360 duplicate_dir(src, dest, &s);
349 duplicate_link(src, dest, &s); 361 else if (S_ISREG(s.st_mode))
350 else { 362 duplicate_file(src, dest, &s);
351 fprintf(stderr, "Error fcopy: src %s is an unsupported type of file\n", src); 363 else if (S_ISLNK(s.st_mode))
352 exit(1); 364 duplicate_link(src, dest, &s);
353 } 365 else {
354 366 fprintf(stderr, "Error fcopy: src %s is an unsupported type of file\n", src);
355 return 0; 367 exit(1);
368 }
369
370 return 0;
356} 371}