]>
Commit | Line | Data |
---|---|---|
e570ca16 AM |
1 | diff -urN coreutils-4.5.10.org/configure.ac coreutils-4.5.10/configure.ac |
2 | --- coreutils-4.5.10.org/configure.ac Mon Mar 24 16:29:50 2003 | |
3 | +++ coreutils-4.5.10/configure.ac Mon Mar 24 16:31:35 2003 | |
4 | @@ -257,6 +257,8 @@ | |
5 | AM_GNU_GETTEXT([external], [need-ngettext]) | |
6 | AM_GNU_GETTEXT_VERSION(0.11.5) | |
7 | ||
8 | +ag_POSIX_ACL | |
9 | + | |
10 | # just in case we want PAM | |
11 | AC_SUBST(LIB_PAM) | |
12 | # with PAM su doesn't need libcrypt | |
13 | diff -urN coreutils-4.5.10.org/lib/acl.c coreutils-4.5.10/lib/acl.c | |
14 | --- coreutils-4.5.10.org/lib/acl.c Mon Mar 24 16:29:46 2003 | |
15 | +++ coreutils-4.5.10/lib/acl.c Mon Mar 24 16:30:58 2003 | |
16 | @@ -22,6 +22,13 @@ | |
17 | # include <config.h> | |
18 | #endif | |
19 | ||
20 | +#if ENABLE_NLS | |
21 | +# include <libintl.h> | |
22 | +# define _(Text) gettext (Text) | |
23 | +#else | |
24 | +# define _(Text) Text | |
25 | +#endif | |
26 | + | |
27 | #include <sys/stat.h> | |
28 | #ifndef S_ISLNK | |
29 | # define S_ISLNK(Mode) 0 | |
30 | @@ -33,6 +40,9 @@ | |
31 | #ifndef ENOSYS | |
32 | # define ENOSYS (-1) | |
33 | #endif | |
34 | +#ifndef ENOTSUP | |
35 | +# define ENOTSUP (-1) | |
36 | +#endif | |
37 | ||
38 | #ifndef MIN_ACL_ENTRIES | |
39 | # define MIN_ACL_ENTRIES 4 | |
40 | @@ -44,19 +54,201 @@ | |
41 | int | |
42 | file_has_acl (char const *path, struct stat const *pathstat) | |
43 | { | |
44 | - /* FIXME: This implementation should work on recent-enough versions | |
45 | - of HP-UX, Solaris, and Unixware, but it simply returns 0 with | |
46 | - POSIX 1003.1e (draft 17 -- abandoned), AIX, GNU/Linux, Irix, and | |
47 | - Tru64. Please see Samba's source/lib/sysacls.c file for | |
48 | - fix-related ideas. */ | |
49 | - | |
50 | #if HAVE_ACL && defined GETACLCNT | |
51 | + /* This implementation should work on recent-enough versions of HP-UX, | |
52 | + Solaris, and Unixware. */ | |
53 | + | |
54 | if (! S_ISLNK (pathstat->st_mode)) | |
55 | { | |
56 | int n = acl (path, GETACLCNT, 0, NULL); | |
57 | return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n); | |
58 | } | |
59 | +#elif HAVE_ACL_EXTENDED_FILE | |
60 | + | |
61 | + /* Linux specific. */ | |
62 | + | |
63 | + if (! S_ISLNK (pathstat->st_mode)) | |
64 | + { | |
65 | + int ret = acl_extended_file (path); | |
66 | + if (ret < 0) | |
67 | + return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1; | |
68 | + return ret; | |
69 | + } | |
70 | +#else | |
71 | + /* FIXME: Add support for AIX, Irix, and Tru64, FreeBSD, etc. | |
72 | + Please see Samba's source/lib/sysacls.c file for fix-related ideas. */ | |
73 | +#endif | |
74 | + | |
75 | + return 0; | |
76 | +} | |
77 | + | |
78 | +/* Copy the permissions from SRC_PATH to DST_PATH, including access control | |
79 | + lists on systems where this is supported. MODE is the file mode for | |
80 | + DST_PATH, including the file type. | |
81 | + Also sets special bits in MODE on DST_PATH. */ | |
82 | + | |
83 | +int | |
84 | +copy_acl (char const *src_path, char const *dst_path, mode_t mode) | |
85 | +{ | |
86 | +#if HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE && \ | |
87 | + HAVE_ACL_ENTRIES | |
88 | + | |
89 | + /* Linux specific. Will work on all POSIX 1003.1e draft 17 (abandoned) | |
90 | + compliant systems if the acl_entries() function is implemented. */ | |
91 | + | |
92 | + acl_t acl = acl_get_file (src_path, ACL_TYPE_ACCESS); | |
93 | + if (acl == NULL) | |
94 | + { | |
95 | + if (errno == ENOSYS || errno == ENOTSUP) | |
96 | + return set_acl (dst_path, mode); | |
97 | + else | |
98 | + { | |
99 | + error (0, errno, "%s", quote (src_path)); | |
100 | + return -1; | |
101 | + } | |
102 | + } | |
103 | + | |
104 | + if (acl_set_file (dst_path, ACL_TYPE_ACCESS, acl)) | |
105 | + { | |
106 | + int saved_errno = errno; | |
107 | + | |
108 | + if (errno == ENOSYS || errno == ENOTSUP) | |
109 | + { | |
110 | + int n = acl_entries (acl); | |
111 | + | |
112 | + acl_free (acl); | |
113 | + if (n == 3) | |
114 | + { | |
115 | + if (chmod (dst_path, mode)) | |
116 | + saved_errno = errno; | |
117 | + else | |
118 | + return 0; | |
119 | + } | |
120 | + else | |
121 | + chmod (dst_path, mode); | |
122 | + } | |
123 | + else | |
124 | + { | |
125 | + acl_free (acl); | |
126 | + chmod (dst_path, mode); | |
127 | + } | |
128 | + error (0, saved_errno, _("preserving permissions for %s"), | |
129 | + quote (dst_path)); | |
130 | + return -1; | |
131 | + } | |
132 | + acl_free (acl); | |
133 | + | |
134 | + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) | |
135 | + { | |
136 | + /* We did not call chmod so far, so the special bits have not yet | |
137 | + been set. */ | |
138 | + | |
139 | + if (chmod (dst_path, mode)) | |
140 | + { | |
141 | + error (0, errno, _("preserving permissions for %s"), | |
142 | + quote (dst_path)); | |
143 | + return -1; | |
144 | + } | |
145 | + } | |
146 | + | |
147 | + if (S_ISDIR (mode)) | |
148 | + { | |
149 | + acl = acl_get_file (src_path, ACL_TYPE_DEFAULT); | |
150 | + if (acl == NULL) | |
151 | + { | |
152 | + error (0, errno, "%s", quote (src_path)); | |
153 | + return -1; | |
154 | + } | |
155 | + | |
156 | + if (acl_set_file (dst_path, ACL_TYPE_DEFAULT, acl)) | |
157 | + { | |
158 | + error (0, errno, _("preserving permissions for %s"), | |
159 | + quote (dst_path)); | |
160 | + acl_free(acl); | |
161 | + return -1; | |
162 | + } | |
163 | + else | |
164 | + acl_free(acl); | |
165 | + } | |
166 | + return 0; | |
167 | +#else | |
168 | + int ret = chmod (dst_path, mode); | |
169 | + if (ret) | |
170 | + error (0, errno, _("preserving permissions for %s"), quote (dst_path)); | |
171 | + return ret; | |
172 | #endif | |
173 | +} | |
174 | + | |
175 | +/* Set the permissions of PATH, overwriting access control lists, on systems | |
176 | + where this is supported. MODE is the file mode for PATH, including the | |
177 | + file type. Also sets special bits in MODE on PATH. */ | |
178 | ||
179 | +int | |
180 | +set_acl (char const *path, mode_t mode) | |
181 | +{ | |
182 | +#if HAVE_ACL_FROM_TEXT && HAVE_ACL_SET_FILE && HAVE_ACL_FREE && \ | |
183 | + HAVE_ACL_DELETE_DEF_FILE | |
184 | + char acl_text[] = "u::---,g::---,o::---"; | |
185 | + acl_t acl; | |
186 | + | |
187 | + if (mode & S_IRUSR) acl_text[ 3] = 'r'; | |
188 | + if (mode & S_IWUSR) acl_text[ 4] = 'w'; | |
189 | + if (mode & S_IXUSR) acl_text[ 5] = 'x'; | |
190 | + if (mode & S_IRGRP) acl_text[10] = 'r'; | |
191 | + if (mode & S_IWGRP) acl_text[11] = 'w'; | |
192 | + if (mode & S_IXGRP) acl_text[12] = 'x'; | |
193 | + if (mode & S_IROTH) acl_text[17] = 'r'; | |
194 | + if (mode & S_IWOTH) acl_text[18] = 'w'; | |
195 | + if (mode & S_IXOTH) acl_text[19] = 'x'; | |
196 | + | |
197 | + acl = acl_from_text(acl_text); | |
198 | + if (!acl) | |
199 | + { | |
200 | + error (0, errno, "%s", quote (path)); | |
201 | + return -1; | |
202 | + } | |
203 | + | |
204 | + if (acl_set_file(path, ACL_TYPE_ACCESS, acl)) | |
205 | + { | |
206 | + int saved_errno = errno; | |
207 | + acl_free (acl); | |
208 | + | |
209 | + if (errno == ENOTSUP || errno == ENOSYS) | |
210 | + { | |
211 | + if (chmod (path, mode)) | |
212 | + saved_errno = errno; | |
213 | + else | |
214 | + return 0; | |
215 | + } | |
216 | + error (0, saved_errno, _("setting permissions for %s"), quote (path)); | |
217 | + return -1; | |
218 | + } | |
219 | + acl_free (acl); | |
220 | + | |
221 | + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) | |
222 | + { | |
223 | + /* We did not call chmod so far, so the special bits have not yet | |
224 | + been set. */ | |
225 | + | |
226 | + if (chmod (path, mode)) | |
227 | + { | |
228 | + error (0, errno, _("preserving permissions for %s"), | |
229 | + quote (path)); | |
230 | + return -1; | |
231 | + } | |
232 | + } | |
233 | + | |
234 | + if (S_ISDIR (mode) && acl_delete_def_file (path)) | |
235 | + { | |
236 | + error (0, errno, _("setting permissions for %s"), quote (path)); | |
237 | + return -1; | |
238 | + } | |
239 | return 0; | |
240 | +#else | |
241 | + int ret = chmod (path, mode); | |
242 | + if (ret) | |
243 | + error (0, errno, _("setting permissions for %s"), quote (path)); | |
244 | + return ret; | |
245 | +#endif | |
246 | } | |
247 | + | |
248 | diff -urN coreutils-4.5.10.org/lib/acl.h coreutils-4.5.10/lib/acl.h | |
249 | --- coreutils-4.5.10.org/lib/acl.h Mon Mar 24 16:29:46 2003 | |
250 | +++ coreutils-4.5.10/lib/acl.h Mon Mar 24 16:30:58 2003 | |
251 | @@ -18,7 +18,7 @@ | |
252 | ||
253 | Written by Paul Eggert. */ | |
254 | ||
255 | -#if HAVE_SYS_ACL_H && HAVE_ACL | |
256 | +#if HAVE_SYS_ACL_H | |
257 | # include <sys/acl.h> | |
258 | #endif | |
259 | #if ! defined GETACLCNT && defined ACL_CNT | |
260 | @@ -26,3 +26,5 @@ | |
261 | #endif | |
262 | ||
263 | int file_has_acl (char const *, struct stat const *); | |
264 | +int copy_acl (char const *, char const *, mode_t); | |
265 | +int set_acl (char const *, mode_t); | |
266 | diff -urN coreutils-4.5.10.org/m4/Makefile.am coreutils-4.5.10/m4/Makefile.am | |
267 | --- coreutils-4.5.10.org/m4/Makefile.am Mon Mar 24 16:29:47 2003 | |
268 | +++ coreutils-4.5.10/m4/Makefile.am Mon Mar 24 16:30:58 2003 | |
269 | @@ -62,6 +62,7 @@ | |
270 | onceonly.m4 \ | |
271 | open-max.m4 \ | |
272 | perl.m4 \ | |
273 | +posix_acl.m4 \ | |
274 | prereq.m4 \ | |
275 | progtest.m4 \ | |
276 | putenv.m4 \ | |
277 | diff -urN coreutils-4.5.10.org/m4/posix_acl.m4 coreutils-4.5.10/m4/posix_acl.m4 | |
278 | --- coreutils-4.5.10.org/m4/posix_acl.m4 Thu Jan 1 01:00:00 1970 | |
279 | +++ coreutils-4.5.10/m4/posix_acl.m4 Mon Mar 24 16:30:58 2003 | |
280 | @@ -0,0 +1,19 @@ | |
281 | +#serial 1 | |
282 | + | |
283 | +dnl Written by Andreas Gruenbacher <a.gruenbacher@computer.org>. | |
284 | + | |
285 | +dnl Posix 1003.1e draft standard 17 (abandoned) and similar | |
286 | +dnl access control list support | |
287 | +AC_DEFUN([ag_POSIX_ACL], | |
288 | +[ | |
289 | + AC_CHECK_HEADERS(sys/acl.h) | |
290 | + AC_CHECK_LIB(acl, main) | |
291 | + AC_CHECK_FUNCS(acl_get_file acl_set_file acl_free acl_to_text \ | |
292 | + acl_from_text acl_delete_def_file) | |
293 | + # Linux specific extensions: | |
294 | + AC_CHECK_FUNCS(acl_entries acl_extended_file) | |
295 | + | |
296 | + if test $ac_cv_header_sys_acl_h = yes; then | |
297 | + AC_DEFINE(USE_ACL, 1, [Define if you want access control list support.]) | |
298 | + fi | |
299 | +]) | |
300 | diff -urN coreutils-4.5.10.org/src/copy.c coreutils-4.5.10/src/copy.c | |
301 | --- coreutils-4.5.10.org/src/copy.c Mon Mar 24 16:29:46 2003 | |
302 | +++ coreutils-4.5.10/src/copy.c Mon Mar 24 16:30:58 2003 | |
303 | @@ -99,26 +99,6 @@ | |
304 | /* The invocation name of this program. */ | |
305 | extern char *program_name; | |
306 | ||
307 | -/* Encapsulate selection of the file mode to be applied to | |
308 | - new non-directories. */ | |
309 | - | |
310 | -static mode_t | |
311 | -get_dest_mode (const struct cp_options *option, mode_t mode) | |
312 | -{ | |
313 | - /* In some applications (e.g., install), use precisely the | |
314 | - specified mode. */ | |
315 | - if (option->set_mode) | |
316 | - return option->mode; | |
317 | - | |
318 | - /* Honor the umask for `cp', but not for `mv' or `cp -p'. | |
319 | - In addition, `cp' without -p must clear the set-user-ID and set-group-ID | |
320 | - bits. POSIX requires it do that when creating new files. */ | |
321 | - if (!option->move_mode && !option->preserve_mode) | |
322 | - mode &= (option->umask_kill & ~(S_ISUID | S_ISGID)); | |
323 | - | |
324 | - return mode; | |
325 | -} | |
326 | - | |
327 | /* FIXME: describe */ | |
328 | /* FIXME: rewrite this to use a hash table so we avoid the quadratic | |
329 | performance hit that's probably noticeable only on trees deeper | |
330 | @@ -792,13 +772,13 @@ | |
331 | struct stat src_sb; | |
332 | struct stat dst_sb; | |
333 | mode_t src_mode; | |
334 | - mode_t src_type; | |
335 | + mode_t dst_mode; | |
336 | char *earlier_file = NULL; | |
337 | char *dst_backup = NULL; | |
338 | int backup_succeeded = 0; | |
339 | int delayed_fail; | |
340 | int copied_as_regular = 0; | |
341 | - int ran_chown = 0; | |
342 | + int dst_mode_valid = 0; | |
343 | int preserve_metadata; | |
344 | ||
345 | if (x->move_mode && rename_succeeded) | |
346 | @@ -811,11 +791,9 @@ | |
347 | return 1; | |
348 | } | |
349 | ||
350 | - src_type = src_sb.st_mode; | |
351 | - | |
352 | src_mode = src_sb.st_mode; | |
353 | ||
354 | - if (S_ISDIR (src_type) && !x->recursive) | |
355 | + if (S_ISDIR (src_mode) && !x->recursive) | |
356 | { | |
357 | error (0, 0, _("omitting directory %s"), quote (src_path)); | |
358 | return 1; | |
359 | @@ -870,7 +848,7 @@ | |
360 | ||
361 | if (!S_ISDIR (dst_sb.st_mode)) | |
362 | { | |
363 | - if (S_ISDIR (src_type)) | |
364 | + if (S_ISDIR (src_mode)) | |
365 | { | |
366 | error (0, 0, | |
367 | _("cannot overwrite non-directory %s with directory %s"), | |
368 | @@ -896,7 +874,7 @@ | |
369 | } | |
370 | } | |
371 | ||
372 | - if (!S_ISDIR (src_type)) | |
373 | + if (!S_ISDIR (src_mode)) | |
374 | { | |
375 | if (S_ISDIR (dst_sb.st_mode)) | |
376 | { | |
377 | @@ -924,7 +902,7 @@ | |
378 | This may be due to an interactive `negative' reply to the | |
379 | prompt about the existing file. It may also be due to the | |
380 | use of the --reply=no option. */ | |
381 | - if (!S_ISDIR (src_type)) | |
382 | + if (!S_ISDIR (src_mode)) | |
383 | { | |
384 | /* cp and mv treat -i and -f differently. */ | |
385 | if (x->move_mode) | |
386 | @@ -1042,7 +1020,7 @@ | |
387 | /* If the source is a directory, we don't always create the destination | |
388 | directory. So --verbose should not announce anything until we're | |
389 | sure we'll create a directory. */ | |
390 | - if (x->verbose && !S_ISDIR (src_type)) | |
391 | + if (x->verbose && !S_ISDIR (src_mode)) | |
392 | { | |
393 | printf ("%s -> %s", quote_n (0, src_path), quote_n (1, dst_path)); | |
394 | if (backup_succeeded) | |
395 | @@ -1077,7 +1055,7 @@ | |
396 | || (command_line_arg | |
397 | && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) | |
398 | || x->dereference == DEREF_ALWAYS)) | |
399 | - || (x->recursive && S_ISDIR (src_type))) | |
400 | + || (x->recursive && S_ISDIR (src_mode))) | |
401 | { | |
402 | earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev); | |
403 | } | |
404 | @@ -1090,7 +1068,7 @@ | |
405 | /* Avoid damaging the destination filesystem by refusing to preserve | |
406 | hard-linked directories (which are found at least in Netapp snapshot | |
407 | directories). */ | |
408 | - if (S_ISDIR (src_type)) | |
409 | + if (S_ISDIR (src_mode)) | |
410 | { | |
411 | /* If src_path and earlier_file refer to the same directory entry, | |
412 | then warn about copying a directory into itself. */ | |
413 | @@ -1142,7 +1120,7 @@ | |
414 | { | |
415 | if (rename (src_path, dst_path) == 0) | |
416 | { | |
417 | - if (x->verbose && S_ISDIR (src_type)) | |
418 | + if (x->verbose && S_ISDIR (src_mode)) | |
419 | printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); | |
420 | if (rename_succeeded) | |
421 | *rename_succeeded = 1; | |
422 | @@ -1255,7 +1233,7 @@ | |
423 | In such cases, set this variable to zero. */ | |
424 | preserve_metadata = 1; | |
425 | ||
426 | - if (S_ISDIR (src_type)) | |
427 | + if (S_ISDIR (src_mode)) | |
428 | { | |
429 | struct dir_list *dir; | |
430 | ||
431 | @@ -1280,16 +1258,38 @@ | |
432 | ||
433 | if (new_dst || !S_ISDIR (dst_sb.st_mode)) | |
434 | { | |
435 | - /* Create the new directory writable and searchable, so | |
436 | - we can create new entries in it. */ | |
437 | - | |
438 | - if (mkdir (dst_path, (src_mode & x->umask_kill) | S_IRWXU)) | |
439 | + if (mkdir (dst_path, src_mode)) | |
440 | { | |
441 | error (0, errno, _("cannot create directory %s"), | |
442 | quote (dst_path)); | |
443 | goto un_backup; | |
444 | } | |
445 | ||
446 | + /* We need search and write permissions to the new directory | |
447 | + for adding the directory's contents. Check if these permissions | |
448 | + are already there. */ | |
449 | + | |
450 | + if (lstat (dst_path, &dst_sb)) | |
451 | + { | |
452 | + error (0, errno, _("cannot stat %s"), quote (dst_path)); | |
453 | + delayed_fail = 1; | |
454 | + } | |
455 | + else if ((dst_sb.st_mode & S_IRWXU) != S_IRWXU) | |
456 | + { | |
457 | + /* Make the new directory writable and searchable. The original | |
458 | + permissions will be restored later. */ | |
459 | + | |
460 | + dst_mode_valid = 1; | |
461 | + dst_mode = dst_sb.st_mode; | |
462 | + | |
463 | + if (chmod (dst_path, dst_mode | S_IRWXU)) | |
464 | + { | |
465 | + error (0, errno, _("setting permissions for %s"), | |
466 | + quote (dst_path)); | |
467 | + goto un_backup; | |
468 | + } | |
469 | + } | |
470 | + | |
471 | /* Insert the created directory's inode and device | |
472 | numbers into the search structure, so that we can | |
473 | avoid copying it again. */ | |
474 | @@ -1365,10 +1365,10 @@ | |
475 | goto un_backup; | |
476 | } | |
477 | } | |
478 | - else if (S_ISREG (src_type) | |
479 | - || (x->copy_as_regular && !S_ISDIR (src_type) | |
480 | + else if (S_ISREG (src_mode) | |
481 | + || (x->copy_as_regular && !S_ISDIR (src_mode) | |
482 | #ifdef S_ISLNK | |
483 | - && !S_ISLNK (src_type) | |
484 | + && !S_ISLNK (src_mode) | |
485 | #endif | |
486 | )) | |
487 | { | |
488 | @@ -1376,15 +1376,14 @@ | |
489 | /* POSIX says the permission bits of the source file must be | |
490 | used as the 3rd argument in the open call, but that's not consistent | |
491 | with historical practice. */ | |
492 | - if (copy_reg (src_path, dst_path, x, | |
493 | - get_dest_mode (x, src_mode), &new_dst, &src_sb)) | |
494 | + if (copy_reg (src_path, dst_path, x, src_mode, &new_dst, &src_sb)) | |
495 | goto un_backup; | |
496 | } | |
497 | else | |
498 | #ifdef S_ISFIFO | |
499 | - if (S_ISFIFO (src_type)) | |
500 | + if (S_ISFIFO (src_mode)) | |
501 | { | |
502 | - if (mkfifo (dst_path, get_dest_mode (x, src_mode))) | |
503 | + if (mkfifo (dst_path, src_mode)) | |
504 | { | |
505 | error (0, errno, _("cannot create fifo %s"), quote (dst_path)); | |
506 | goto un_backup; | |
507 | @@ -1392,13 +1391,13 @@ | |
508 | } | |
509 | else | |
510 | #endif | |
511 | - if (S_ISBLK (src_type) || S_ISCHR (src_type) | |
512 | + if (S_ISBLK (src_mode) || S_ISCHR (src_mode) | |
513 | #ifdef S_ISSOCK | |
514 | - || S_ISSOCK (src_type) | |
515 | + || S_ISSOCK (src_mode) | |
516 | #endif | |
517 | ) | |
518 | { | |
519 | - if (mknod (dst_path, get_dest_mode (x, src_mode), src_sb.st_rdev)) | |
520 | + if (mknod (dst_path, src_mode, src_sb.st_rdev)) | |
521 | { | |
522 | error (0, errno, _("cannot create special file %s"), | |
523 | quote (dst_path)); | |
524 | @@ -1407,7 +1406,7 @@ | |
525 | } | |
526 | else | |
527 | #ifdef S_ISLNK | |
528 | - if (S_ISLNK (src_type)) | |
529 | + if (S_ISLNK (src_mode)) | |
530 | { | |
531 | char *src_link_val = xreadlink (src_path); | |
532 | if (src_link_val == NULL) | |
533 | @@ -1513,7 +1512,25 @@ | |
534 | if (x->preserve_ownership | |
535 | && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) | |
536 | { | |
537 | - ran_chown = 1; | |
538 | + /* The chown() system call may clear the SUID and SGID bits, so we | |
539 | + need to set them again later. (But we don't care if we will | |
540 | + overwrite the permissions of the destination file anyway.) */ | |
541 | + | |
542 | + if ((src_mode & (S_ISUID | S_ISGID)) | |
543 | + && !x->preserve_mode && !x->move_mode && !x->set_mode) | |
544 | + { | |
545 | + if (lstat (dst_path, &dst_sb)) | |
546 | + { | |
547 | + error (0, errno, _("cannot stat %s"), quote (dst_path)); | |
548 | + delayed_fail = 1; | |
549 | + } | |
550 | + else | |
551 | + { | |
552 | + dst_mode_valid = 1; | |
553 | + dst_mode = dst_sb.st_mode; | |
554 | + } | |
555 | + } | |
556 | + | |
557 | if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) | |
558 | { | |
559 | error (0, errno, _("failed to preserve ownership for %s"), | |
560 | @@ -1534,20 +1551,23 @@ | |
561 | } | |
562 | #endif | |
563 | ||
564 | - /* Permissions of newly-created regular files were set upon `open' in | |
565 | - copy_reg. But don't return early if there were any special bits and | |
566 | - we had to run chown, because the chown must have reset those bits. */ | |
567 | - if ((new_dst && copied_as_regular) | |
568 | - && !(ran_chown && (src_mode & ~S_IRWXUGO))) | |
569 | - return delayed_fail; | |
570 | - | |
571 | - if ((x->preserve_mode || new_dst) | |
572 | - && (x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type))) | |
573 | + if (x->preserve_mode || x->move_mode) | |
574 | { | |
575 | - if (chmod (dst_path, get_dest_mode (x, src_mode))) | |
576 | - { | |
577 | - error (0, errno, _("setting permissions for %s"), quote (dst_path)); | |
578 | - if (x->set_mode || x->require_preserve) | |
579 | + if (copy_acl (src_path, dst_path, src_mode) && x->require_preserve) | |
580 | + return 1; | |
581 | + } | |
582 | + else if (x->set_mode) | |
583 | + { | |
584 | + if (set_acl (dst_path, x->mode) && x->require_preserve) | |
585 | + return 1; | |
586 | + } | |
587 | + else if (dst_mode_valid) | |
588 | + { | |
589 | + if (chmod (dst_path, dst_mode)) | |
590 | + { | |
591 | + error (0, errno, _("preserving permissions for %s"), | |
592 | + quote (dst_path)); | |
593 | + if (x->require_preserve) | |
594 | return 1; | |
595 | } | |
596 | } | |
597 | diff -urN coreutils-4.5.10.org/src/copy.h coreutils-4.5.10/src/copy.h | |
598 | --- coreutils-4.5.10.org/src/copy.h Mon Mar 24 16:29:46 2003 | |
599 | +++ coreutils-4.5.10/src/copy.h Mon Mar 24 16:30:58 2003 | |
600 | @@ -139,9 +139,6 @@ | |
601 | Create destination directories as usual. */ | |
602 | int symbolic_link; | |
603 | ||
604 | - /* The bits to preserve in created files' modes. */ | |
605 | - mode_t umask_kill; | |
606 | - | |
607 | /* If nonzero, do not copy a nondirectory that has an existing destination | |
608 | with the same or newer modification time. */ | |
609 | int update; | |
610 | diff -urN coreutils-4.5.10.org/src/cp.c coreutils-4.5.10/src/cp.c | |
611 | --- coreutils-4.5.10.org/src/cp.c Mon Mar 24 16:29:46 2003 | |
612 | +++ coreutils-4.5.10/src/cp.c Mon Mar 24 16:34:26 2003 | |
613 | @@ -61,7 +61,8 @@ | |
614 | need to be fixed after copying. */ | |
615 | struct dir_attr | |
616 | { | |
617 | - int is_new_dir; | |
618 | + int mode_valid; | |
619 | + mode_t mode; | |
620 | int slash_offset; | |
621 | struct dir_attr *next; | |
622 | }; | |
623 | @@ -342,9 +343,14 @@ | |
624 | } | |
625 | } | |
626 | ||
627 | - if (x->preserve_mode || p->is_new_dir) | |
628 | + if (x->preserve_mode) | |
629 | { | |
630 | - if (chmod (dst_path, src_sb.st_mode & x->umask_kill)) | |
631 | + if (copy_acl (src_path, dst_path, src_sb.st_mode)) | |
632 | + return 1; | |
633 | + } | |
634 | + else if (p->mode_valid) | |
635 | + { | |
636 | + if (chmod (dst_path, p->mode)) | |
637 | { | |
638 | error (0, errno, _("failed to preserve permissions for %s"), | |
639 | quote (dst_path)); | |
640 | @@ -362,8 +368,7 @@ | |
641 | ||
642 | SRC_OFFSET is the index in CONST_DIRPATH (which is a destination | |
643 | path) of the beginning of the source directory name. | |
644 | - Create any leading directories that don't already exist, | |
645 | - giving them permissions MODE. | |
646 | + Create any leading directories that don't already exist. | |
647 | If VERBOSE_FMT_STRING is nonzero, use it as a printf format | |
648 | string for printing a message after successfully making a directory. | |
649 | The format should take two string arguments: the names of the | |
650 | @@ -378,15 +383,16 @@ | |
651 | /* FIXME: find a way to synch this function with the one in lib/makepath.c. */ | |
652 | ||
653 | static int | |
654 | -make_path_private (const char *const_dirpath, int src_offset, int mode, | |
655 | +make_path_private (const char *const_dirpath, int src_offset, | |
656 | const char *verbose_fmt_string, struct dir_attr **attr_list, | |
657 | - int *new_dst, int (*xstat)()) | |
658 | + int *new_dst, const struct cp_options *x) | |
659 | { | |
660 | struct stat stats; | |
661 | char *dirpath; /* A copy of CONST_DIRPATH we can change. */ | |
662 | char *src; /* Source name in `dirpath'. */ | |
663 | char *dst_dirname; /* Leading path of `dirpath'. */ | |
664 | size_t dirlen; /* Length of leading path of `dirpath'. */ | |
665 | + mode_t mode; | |
666 | ||
667 | dirpath = (char *) alloca (strlen (const_dirpath) + 1); | |
668 | strcpy (dirpath, const_dirpath); | |
669 | @@ -400,7 +406,7 @@ | |
670 | ||
671 | *attr_list = NULL; | |
672 | ||
673 | - if ((*xstat) (dst_dirname, &stats)) | |
674 | + if ((*x->xstat) (dst_dirname, &stats)) | |
675 | { | |
676 | /* Parent of CONST_DIRNAME does not exist. | |
677 | Make all missing intermediate directories. */ | |
678 | @@ -420,15 +426,23 @@ | |
679 | *attr_list = new; | |
680 | ||
681 | *slash = '\0'; | |
682 | - if ((*xstat) (dirpath, &stats)) | |
683 | + if ((*x->xstat) (dirpath, &stats)) | |
684 | { | |
685 | /* This element of the path does not exist. We must set | |
686 | - *new_dst and new->is_new_dir inside this loop because, | |
687 | + *new_dst inside this loop because, | |
688 | for example, in the command `cp --parents ../a/../b/c e_dir', | |
689 | make_path_private creates only e_dir/../a if ./b already | |
690 | exists. */ | |
691 | *new_dst = 1; | |
692 | - new->is_new_dir = 1; | |
693 | + | |
694 | + if ((*x->xstat) (src, &stats)) | |
695 | + { | |
696 | + error (0, errno, _("failed to get attributes of %s"), | |
697 | + quote (src)); | |
698 | + return 1; | |
699 | + } | |
700 | + mode = stats.st_mode; | |
701 | + | |
702 | if (mkdir (dirpath, mode)) | |
703 | { | |
704 | error (0, errno, _("cannot make directory %s"), | |
705 | @@ -440,6 +454,46 @@ | |
706 | if (verbose_fmt_string != NULL) | |
707 | printf (verbose_fmt_string, src, dirpath); | |
708 | } | |
709 | + | |
710 | + /* We need search and write permissions to the new directory | |
711 | + for adding the directory's contents. Check if these | |
712 | + permissions are already there. */ | |
713 | + | |
714 | + if (lstat (dirpath, &stats)) | |
715 | + { | |
716 | + error (0, errno, _("failed to get attributes of %s"), | |
717 | + quote (dirpath)); | |
718 | + return 1; | |
719 | + } | |
720 | + else | |
721 | + { | |
722 | + if (x->preserve_mode && mode != stats.st_mode) | |
723 | + { | |
724 | + new->mode = mode; | |
725 | + new->mode_valid = 1; | |
726 | + } | |
727 | + else | |
728 | + new->mode_valid = 0; | |
729 | + | |
730 | + if ((stats.st_mode & S_IRWXU) != S_IRWXU) | |
731 | + { | |
732 | + /* Make the new directory writable and searchable. The | |
733 | + original permissions will be restored later. */ | |
734 | + | |
735 | + if (!new->mode_valid) | |
736 | + { | |
737 | + new->mode = stats.st_mode; | |
738 | + new->mode_valid = 1; | |
739 | + } | |
740 | + | |
741 | + if (chmod (dirpath, stats.st_mode | S_IRWXU)) | |
742 | + { | |
743 | + error (0, errno, _("setting permissions for %s"), | |
744 | + quote (dirpath)); | |
745 | + return 1; | |
746 | + } | |
747 | + } | |
748 | + } | |
749 | } | |
750 | else if (!S_ISDIR (stats.st_mode)) | |
751 | { | |
752 | @@ -449,7 +503,7 @@ | |
753 | } | |
754 | else | |
755 | { | |
756 | - new->is_new_dir = 0; | |
757 | + new->mode_valid = 0; | |
758 | *new_dst = 0; | |
759 | } | |
760 | *slash++ = '/'; | |
761 | @@ -600,11 +654,9 @@ | |
762 | leading directories. */ | |
763 | parent_exists = !make_path_private (dst_path, | |
764 | arg_in_concat - dst_path, | |
765 | - S_IRWXU, | |
766 | (x->verbose | |
767 | ? "%s -> %s\n" : NULL), | |
768 | - &attr_list, &new_dst, | |
769 | - x->xstat); | |
770 | + &attr_list, &new_dst, x); | |
771 | } | |
772 | else | |
773 | { | |
774 | @@ -739,12 +791,6 @@ | |
775 | /* Not used. */ | |
776 | x->stdin_tty = 0; | |
777 | ||
778 | - /* Find out the current file creation mask, to knock the right bits | |
779 | - when using chmod. The creation mask is set to be liberal, so | |
780 | - that created directories can be written, even if it would not | |
781 | - have been allowed with the mask this process was started with. */ | |
782 | - x->umask_kill = ~ umask (0); | |
783 | - | |
784 | x->update = 0; | |
785 | x->verbose = 0; | |
786 | x->dest_info = NULL; | |
787 | @@ -1017,9 +1063,6 @@ | |
788 | version_control_string) | |
789 | : none); | |
790 | ||
791 | - if (x.preserve_mode == 1) | |
792 | - x.umask_kill = ~ (mode_t) 0; | |
793 | - | |
794 | if (x.dereference == DEREF_UNDEFINED) | |
795 | { | |
796 | if (x.recursive) | |
797 | diff -urN coreutils-4.5.10.org/src/install.c coreutils-4.5.10/src/install.c | |
798 | --- coreutils-4.5.10.org/src/install.c Mon Mar 24 16:29:46 2003 | |
799 | +++ coreutils-4.5.10/src/install.c Mon Mar 24 16:30:58 2003 | |
800 | @@ -245,7 +245,6 @@ | |
801 | x->mode = S_IRUSR | S_IWUSR; | |
802 | x->stdin_tty = 0; | |
803 | ||
804 | - x->umask_kill = 0; | |
805 | x->update = 0; | |
806 | x->verbose = 0; | |
807 | x->xstat = stat; | |
808 | diff -urN coreutils-4.5.10.org/src/ls.c coreutils-4.5.10/src/ls.c | |
809 | --- coreutils-4.5.10.org/src/ls.c Mon Mar 24 16:29:46 2003 | |
810 | +++ coreutils-4.5.10/src/ls.c Mon Mar 24 16:30:58 2003 | |
811 | @@ -223,13 +223,13 @@ | |
812 | ||
813 | enum filetype filetype; | |
814 | ||
815 | -#if HAVE_ACL | |
816 | +#if HAVE_ACL || USE_ACL | |
817 | /* For long listings, true if the file has an access control list. */ | |
818 | bool have_acl; | |
819 | #endif | |
820 | }; | |
821 | ||
822 | -#if HAVE_ACL | |
823 | +#if HAVE_ACL || USE_ACL | |
824 | # define FILE_HAS_ACL(F) ((F)->have_acl) | |
825 | #else | |
826 | # define FILE_HAS_ACL(F) 0 | |
827 | @@ -2400,7 +2400,7 @@ | |
828 | return 0; | |
829 | } | |
830 | ||
831 | -#if HAVE_ACL | |
832 | +#if HAVE_ACL || USE_ACL | |
833 | if (format == long_format) | |
834 | { | |
835 | int n = file_has_acl (path, &files[files_index].stat); | |
836 | diff -urN coreutils-4.5.10.org/src/mv.c coreutils-4.5.10/src/mv.c | |
837 | --- coreutils-4.5.10.org/src/mv.c Mon Mar 24 16:29:46 2003 | |
838 | +++ coreutils-4.5.10/src/mv.c Mon Mar 24 16:30:58 2003 | |
839 | @@ -137,12 +137,6 @@ | |
840 | x->mode = 0; | |
841 | x->stdin_tty = isatty (STDIN_FILENO); | |
842 | ||
843 | - /* Find out the current file creation mask, to knock the right bits | |
844 | - when using chmod. The creation mask is set to be liberal, so | |
845 | - that created directories can be written, even if it would not | |
846 | - have been allowed with the mask this process was started with. */ | |
847 | - x->umask_kill = ~ umask (0); | |
848 | - | |
849 | x->update = 0; | |
850 | x->verbose = 0; | |
851 | x->xstat = lstat; | |
852 | diff -urN coreutils-4.5.10.org/tests/misc/README coreutils-4.5.10/tests/misc/README | |
853 | --- coreutils-4.5.10.org/tests/misc/README Thu Jan 1 01:00:00 1970 | |
854 | +++ coreutils-4.5.10/tests/misc/README Mon Mar 24 16:30:58 2003 | |
855 | @@ -0,0 +1,6 @@ | |
856 | +Use the run script to run any of the *.test scripts, e.g., | |
857 | + | |
858 | + run cp.test | |
859 | + | |
860 | +The cp.test script can be run as any user; the cp-root | |
861 | +script requires root privileges. | |
862 | diff -urN coreutils-4.5.10.org/tests/misc/acl coreutils-4.5.10/tests/misc/acl | |
863 | --- coreutils-4.5.10.org/tests/misc/acl Thu Jan 1 01:00:00 1970 | |
864 | +++ coreutils-4.5.10/tests/misc/acl Mon Mar 24 16:30:58 2003 | |
865 | @@ -0,0 +1,3 @@ | |
866 | +#!/bin/sh | |
867 | + | |
868 | +getfacl "$@" | sed -e 's/[ ]*#.*$//' -e '/^$/d' | |
869 | diff -urN coreutils-4.5.10.org/tests/misc/cp-root.test coreutils-4.5.10/tests/misc/cp-root.test | |
870 | --- coreutils-4.5.10.org/tests/misc/cp-root.test Thu Jan 1 01:00:00 1970 | |
871 | +++ coreutils-4.5.10/tests/misc/cp-root.test Mon Mar 24 16:30:58 2003 | |
872 | @@ -0,0 +1,26 @@ | |
873 | +! Tests the access control list extensions to cp. | |
874 | +! This script must be run as root. | |
875 | +! | |
876 | +$ rm -rf test | |
877 | +$ mkdir test | |
878 | +$ cd test | |
879 | +$ umask 022 | |
880 | +$ touch f | |
881 | +$ chmod u+xs,g+xs f | |
882 | +$ mode f | |
883 | + -rwsr-sr-- f | |
884 | +$ cp -p f g | |
885 | +$ mode g | |
886 | + -rwsr-sr-- g | |
887 | +$ cp f h | |
888 | +$ mode h | |
889 | + -rwsr-sr-- h | |
890 | +$ chown bin h | |
891 | +$ cp h i | |
892 | +$ mode i | |
893 | + -rwsr-sr-- i | |
894 | +! | |
895 | +! cleanup | |
896 | +! | |
897 | +$cd .. | |
898 | +$ rm -rf test | |
899 | diff -urN coreutils-4.5.10.org/tests/misc/cp.test coreutils-4.5.10/tests/misc/cp.test | |
900 | --- coreutils-4.5.10.org/tests/misc/cp.test Thu Jan 1 01:00:00 1970 | |
901 | +++ coreutils-4.5.10/tests/misc/cp.test Mon Mar 24 16:30:58 2003 | |
902 | @@ -0,0 +1,86 @@ | |
903 | +! Tests the access control list extensions to cp (and also of ls). | |
904 | +! Requires a system with POSIX access control lists and the | |
905 | +! getfacl and setfacl utilities. | |
906 | +! | |
907 | +$ rm -rf test | |
908 | +$ mkdir test | |
909 | +$ cd test | |
910 | +$ umask 022 | |
911 | +$ touch f | |
912 | +$ mode . f | |
913 | + drwxr-xr-x . | |
914 | + -rw-r--r-- f | |
915 | +$ setfacl -m u:@OWNER@:rw- f | |
916 | +$ mode f | |
917 | + -rw-rw-r--+ f | |
918 | +$ acl f | |
919 | + user::rw- | |
920 | + user:@OWNER@:rw- | |
921 | + group::r-- | |
922 | + mask::rw- | |
923 | + other::r-- | |
924 | +! | |
925 | +! cp and cp -p | |
926 | +! | |
927 | +$ cp f g | |
928 | +$ cp -p f h | |
929 | +$ mode g h | |
930 | + -rw-r--r-- g | |
931 | + -rw-rw-r--+ h | |
932 | +$ acl h | |
933 | + user::rw- | |
934 | + user:@OWNER@:rw- | |
935 | + group::r-- | |
936 | + mask::rw- | |
937 | + other::r-- | |
938 | +$ mkdir d | |
939 | +$ setfacl -d -m u::rwx,u:@OWNER@:r-x,g::---,m::r-x,o::--- d | |
940 | +$ acl d | |
941 | + user::rwx | |
942 | + group::r-x | |
943 | + other::r-x | |
944 | + default:user::rwx | |
945 | + default:user:@OWNER@:r-x | |
946 | + default:group::--- | |
947 | + default:mask::r-x | |
948 | + default:other::--- | |
949 | +$ touch d/i | |
950 | +$ acl d/i | |
951 | + user::rw- | |
952 | + user:@OWNER@:r-x | |
953 | + group::--- | |
954 | + mask::r-- | |
955 | + other::--- | |
956 | +$ cp f d/f | |
957 | +$ acl d/f | |
958 | + user::rw- | |
959 | + user:@OWNER@:r-x | |
960 | + group::--- | |
961 | + mask::r-- | |
962 | + other::--- | |
963 | +$ chmod go-rwx g | |
964 | +$ cp g d/g | |
965 | +$ acl d/g | |
966 | + user::rw- | |
967 | + user:@OWNER@:r-x | |
968 | + group::--- | |
969 | + mask::--- | |
970 | + other::--- | |
971 | +$ cp -p h d/h | |
972 | +$ acl h | |
973 | + user::rw- | |
974 | + user:@OWNER@:rw- | |
975 | + group::r-- | |
976 | + mask::rw- | |
977 | + other::r-- | |
978 | +$ touch j | |
979 | +$ cp -p j d/j | |
980 | +$ mode d/j | |
981 | + -rw-r--r-- d/j | |
982 | +$ | |
983 | +! mv | |
984 | +! | |
985 | +! cleanup | |
986 | +! | |
987 | +$cd .. | |
988 | +$ rm -rf test | |
989 | diff -urN coreutils-4.5.10.org/tests/misc/mode coreutils-4.5.10/tests/misc/mode | |
990 | --- coreutils-4.5.10.org/tests/misc/mode Thu Jan 1 01:00:00 1970 | |
991 | +++ coreutils-4.5.10/tests/misc/mode Mon Mar 24 16:30:58 2003 | |
992 | @@ -0,0 +1,2 @@ | |
993 | +#!/bin/sh | |
994 | +ls -dl $* | awk -- '!/^total/ { print $1, $8; }' | |
995 | diff -urN coreutils-4.5.10.org/tests/misc/run coreutils-4.5.10/tests/misc/run | |
996 | --- coreutils-4.5.10.org/tests/misc/run Thu Jan 1 01:00:00 1970 | |
997 | +++ coreutils-4.5.10/tests/misc/run Mon Mar 24 16:30:58 2003 | |
998 | @@ -0,0 +1,164 @@ | |
999 | +#!/usr/bin/perl | |
1000 | + | |
1001 | +use strict; | |
1002 | +use FileHandle; | |
1003 | +use POSIX qw(geteuid getegid isatty); | |
1004 | + | |
1005 | +my $pwd = `pwd`; | |
1006 | +chomp $pwd; | |
1007 | +$ENV{'PATH'} = $pwd . ":../../src:" . $ENV{'PATH'}; | |
1008 | + | |
1009 | +my $owner = getpwuid(geteuid()); | |
1010 | +my $group = getgrgid(getegid()); | |
1011 | + | |
1012 | +my ($OK, $FAILED) = ("ok", "failed"); | |
1013 | +if (isatty(fileno(STDOUT))) { | |
1014 | + $OK = "\033[32m" . $OK . "\033[m"; | |
1015 | + $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m"; | |
1016 | +} | |
1017 | + | |
1018 | +my ($prog, $in, $out) = ([], [], []); | |
1019 | +my $line = 0; | |
1020 | +my $prog_line; | |
1021 | +my ($tests, $failed); | |
1022 | + | |
1023 | +for (;;) { | |
1024 | + my $script = <>; $line++; | |
1025 | + $script =~ s/\@OWNER\@/$owner/g; | |
1026 | + $script =~ s/\@GROUP\@/$group/g; | |
1027 | + next if (defined($script) && $script =~ /^!/); | |
1028 | + if (!defined($script) || $script =~ s/^\$ ?//) { | |
1029 | + if (@$prog) { | |
1030 | + #print "[$prog_line] \$ ", join(' ', @$prog), " -- "; | |
1031 | + my $p = [ @$prog ]; | |
1032 | + print "[$prog_line] \$ ", join(' ', | |
1033 | + map { s/\s/\\$&/g; $_ } @$p), " -- "; | |
1034 | + my $result = exec_test($prog, $in); | |
1035 | + my $good = 1; | |
1036 | + my $nmax = (@$out > @$result) ? @$out : @$result; | |
1037 | + for (my $n=0; $n < $nmax; $n++) { | |
1038 | + if (!defined($out->[$n]) || !defined($result->[$n]) || | |
1039 | + $out->[$n] ne $result->[$n]) { | |
1040 | + $good = 0; | |
1041 | + #chomp $out->[$n]; | |
1042 | + #chomp $result->[$n]; | |
1043 | + #print "$out->[$n] != $result->[$n]"; | |
1044 | + } | |
1045 | + } | |
1046 | + $tests++; | |
1047 | + $failed++ unless $good; | |
1048 | + print $good ? $OK : $FAILED, "\n"; | |
1049 | + if (!$good) { | |
1050 | + for (my $n=0; $n < $nmax; $n++) { | |
1051 | + my $l = defined($out->[$n]) ? $out->[$n] : "~"; | |
1052 | + chomp $l; | |
1053 | + my $r = defined($result->[$n]) ? $result->[$n] : "~"; | |
1054 | + chomp $r; | |
1055 | + print sprintf("%-37s | %-39s\n", $l, $r); | |
1056 | + } | |
1057 | + } | |
1058 | + } | |
1059 | + #$prog = [ split /\s+/, $script ] if $script; | |
1060 | + $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $script ] if $script; | |
1061 | + $prog_line = $line; | |
1062 | + $in = []; | |
1063 | + $out = []; | |
1064 | + } elsif ($script =~ s/^> ?//) { | |
1065 | + push @$in, $script; | |
1066 | + } else { | |
1067 | + $script =~ s/^[ \t]*//; # ignore leading whitespace | |
1068 | + push @$out, $script; | |
1069 | + } | |
1070 | + last unless defined($script); | |
1071 | +} | |
1072 | +my $status = sprintf("%d commands (%d passed, %d failed)", | |
1073 | + $tests, $tests-$failed, $failed); | |
1074 | +if (isatty(fileno(STDOUT))) { | |
1075 | + if ($failed) { | |
1076 | + $status = "\033[31m\033[1m" . $status . "\033[m"; | |
1077 | + } else { | |
1078 | + $status = "\033[32m" . $status . "\033[m"; | |
1079 | + } | |
1080 | +} | |
1081 | +print $status, "\n"; | |
1082 | + | |
1083 | +sub exec_test($$) { | |
1084 | + my ($prog, $in) = @_; | |
1085 | + local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2); | |
1086 | + | |
1087 | + if ($prog->[0] eq "umask") { | |
1088 | + umask oct $prog->[1]; | |
1089 | + return []; | |
1090 | + } elsif ($prog->[0] eq "cd") { | |
1091 | + if (!chdir $prog->[1]) { | |
1092 | + return [ "chdir: $prog->[1]: $!\n" ]; | |
1093 | + } | |
1094 | + return []; | |
1095 | + } | |
1096 | + | |
1097 | + pipe *IN2, *OUT | |
1098 | + or die "Can't create pipe for reading: $!"; | |
1099 | + open *IN_DUP, "<&STDIN" | |
1100 | + or *IN_DUP = undef; | |
1101 | + open *STDIN, "<&IN2" | |
1102 | + or die "Can't duplicate pipe for reading: $!"; | |
1103 | + close *IN2; | |
1104 | + | |
1105 | + open *OUT_DUP, ">&STDOUT" | |
1106 | + or die "Can't duplicate STDOUT: $!"; | |
1107 | + pipe *IN, *OUT2 | |
1108 | + or die "Can't create pipe for writing: $!"; | |
1109 | + open *STDOUT, ">&OUT2" | |
1110 | + or die "Can't duplicate pipe for writing: $!"; | |
1111 | + close *OUT2; | |
1112 | + | |
1113 | + *STDOUT->autoflush(); | |
1114 | + *OUT->autoflush(); | |
1115 | + | |
1116 | + if (fork()) { | |
1117 | + # Server | |
1118 | + if (*IN_DUP) { | |
1119 | + open *STDIN, "<&IN_DUP" | |
1120 | + or die "Can't duplicate STDIN: $!"; | |
1121 | + close *IN_DUP | |
1122 | + or die "Can't close STDIN duplicate: $!"; | |
1123 | + } | |
1124 | + open *STDOUT, ">&OUT_DUP" | |
1125 | + or die "Can't duplicate STDOUT: $!"; | |
1126 | + close *OUT_DUP | |
1127 | + or die "Can't close STDOUT duplicate: $!"; | |
1128 | + | |
1129 | + foreach my $line (@$in) { | |
1130 | + #print "> $line"; | |
1131 | + print OUT $line; | |
1132 | + } | |
1133 | + close *OUT | |
1134 | + or die "Can't close pipe for writing: $!"; | |
1135 | + | |
1136 | + my $result = []; | |
1137 | + while (<IN>) { | |
1138 | + #print "< $_"; | |
1139 | + push @$result, $_; | |
1140 | + } | |
1141 | + return $result; | |
1142 | + } else { | |
1143 | + # Client | |
1144 | + close IN | |
1145 | + or die "Can't close read end for input pipe: $!"; | |
1146 | + close OUT | |
1147 | + or die "Can't close write end for output pipe: $!"; | |
1148 | + close OUT_DUP | |
1149 | + or die "Can't close STDOUT duplicate: $!"; | |
1150 | + local *ERR_DUP; | |
1151 | + open ERR_DUP, ">&STDERR" | |
1152 | + or die "Can't duplicate STDERR: $!"; | |
1153 | + open STDERR, ">&STDOUT" | |
1154 | + or die "Can't join STDOUT and STDERR: $!"; | |
1155 | + | |
1156 | + #print ERR_DUP "<", join(' ', @$prog), ">\n"; | |
1157 | + exec @$prog; | |
1158 | + print ERR_DUP $prog->[0], ": $!\n"; | |
1159 | + exit; | |
1160 | + } | |
1161 | +} | |
1162 | + |