1 /* Test whether two files have the same ACLs.
2 Copyright (C) 2008-2017 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2008. */
27 #if HAVE_ACL_GET_FILE || HAVE_FACL || HAVE_GETACL || HAVE_ACLX_GET || HAVE_STATACL || HAVE_ACLSORT
28 # include <sys/types.h>
32 # include <sys/types.h>
36 #include "read-file.h"
41 main (int argc
, char *argv
[])
51 /* Compare the contents of the two files. */
58 contents1
= read_file (file1
, &size1
);
59 if (contents1
== NULL
)
61 fprintf (stderr
, "error reading file %s: errno = %d\n", file1
, errno
);
65 contents2
= read_file (file2
, &size2
);
66 if (contents2
== NULL
)
68 fprintf (stderr
, "error reading file %s: errno = %d\n", file2
, errno
);
75 fprintf (stderr
, "files %s and %s have different sizes\n",
80 if (memcmp (contents1
, contents2
, size1
) != 0)
82 fprintf (stderr
, "files %s and %s have different contents\n",
89 /* Compare the access permissions of the two files, including ACLs. */
94 if (stat (file1
, &statbuf1
) < 0)
96 fprintf (stderr
, "error accessing file %s: errno = %d\n", file1
, errno
);
100 if (stat (file2
, &statbuf2
) < 0)
102 fprintf (stderr
, "error accessing file %s: errno = %d\n", file2
, errno
);
106 if (statbuf1
.st_mode
!= statbuf2
.st_mode
)
108 fprintf (stderr
, "files %s and %s have different access modes: %03o and %03o\n",
110 (unsigned int) statbuf1
.st_mode
, (unsigned int) statbuf2
.st_mode
);
115 #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
116 static const int types
[] =
119 # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
125 for (t
= 0; t
< sizeof (types
) / sizeof (types
[0]); t
++)
135 acl1
= acl_get_file (file1
, type
);
136 if (acl1
== (acl_t
)NULL
)
143 text1
= acl_to_text (acl1
, NULL
);
149 acl2
= acl_get_file (file2
, type
);
150 if (acl2
== (acl_t
)NULL
)
157 text2
= acl_to_text (acl2
, NULL
);
164 if (acl1
!= (acl_t
)NULL
)
166 if (acl2
!= (acl_t
)NULL
)
172 if (strcmp (text1
, text2
) != 0)
174 fprintf (stderr
, "files %s and %s have different ACLs:\n%s\n%s\n",
175 file1
, file2
, text1
, text2
);
181 fprintf (stderr
, "file %s has a valid ACL, but file %s has an invalid ACL\n",
190 fprintf (stderr
, "file %s has an invalid ACL, but file %s has a valid ACL\n",
196 if (errno1
!= errno2
)
198 fprintf (stderr
, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
199 file1
, file2
, errno1
, errno2
);
207 fprintf (stderr
, "file %s has an ACL, but file %s has no ACL\n",
214 if (acl2
!= (acl_t
)NULL
)
216 fprintf (stderr
, "file %s has no ACL, but file %s has an ACL\n",
222 #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
226 count1
= acl (file1
, GETACLCNT
, 0, NULL
);
227 if (count1
< 0 && errno
== ENOSYS
) /* Can happen on Solaris 10 with ZFS */
229 count2
= acl (file2
, GETACLCNT
, 0, NULL
);
230 if (count2
< 0 && errno
== ENOSYS
) /* Can happen on Solaris 10 with ZFS */
235 fprintf (stderr
, "error accessing the ACLs of file %s\n", file1
);
241 fprintf (stderr
, "error accessing the ACLs of file %s\n", file2
);
245 if (count1
!= count2
)
247 fprintf (stderr
, "files %s and %s have different number of ACLs: %d and %d\n",
248 file1
, file2
, count1
, count2
);
253 aclent_t
*entries1
= XNMALLOC (count1
, aclent_t
);
254 aclent_t
*entries2
= XNMALLOC (count2
, aclent_t
);
257 if (count1
> 0 && acl (file1
, GETACL
, count1
, entries1
) < count1
)
259 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file1
);
263 if (count2
> 0 && acl (file2
, GETACL
, count2
, entries2
) < count1
)
265 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file2
);
269 for (i
= 0; i
< count1
; i
++)
271 if (entries1
[i
].a_type
!= entries2
[i
].a_type
)
273 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
274 file1
, file2
, i
, entries1
[i
].a_type
, entries2
[i
].a_type
);
277 if (entries1
[i
].a_id
!= entries2
[i
].a_id
)
279 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
280 file1
, file2
, i
, (int)entries1
[i
].a_id
, (int)entries2
[i
].a_id
);
283 if (entries1
[i
].a_perm
!= entries2
[i
].a_perm
)
285 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
286 file1
, file2
, i
, (unsigned int) entries1
[i
].a_perm
, (unsigned int) entries2
[i
].a_perm
);
292 count1
= acl (file1
, ACE_GETACLCNT
, 0, NULL
);
293 if (count1
< 0 && errno
== EINVAL
)
295 count2
= acl (file2
, ACE_GETACLCNT
, 0, NULL
);
296 if (count2
< 0 && errno
== EINVAL
)
300 fprintf (stderr
, "error accessing the ACE-ACLs of file %s\n", file1
);
306 fprintf (stderr
, "error accessing the ACE-ACLs of file %s\n", file2
);
311 ace_t
*entries1
= XNMALLOC (count1
, ace_t
);
312 ace_t
*entries2
= XNMALLOC (count2
, ace_t
);
316 ret
= acl (file1
, ACE_GETACL
, count1
, entries1
);
317 if (ret
< 0 && errno
== EINVAL
)
319 else if (ret
< count1
)
321 fprintf (stderr
, "error retrieving the ACE-ACLs of file %s\n", file1
);
325 ret
= acl (file2
, ACE_GETACL
, count2
, entries2
);
326 if (ret
< 0 && errno
== EINVAL
)
328 else if (ret
< count2
)
330 fprintf (stderr
, "error retrieving the ACE-ACLs of file %s\n", file2
);
335 if (count1
!= count2
)
337 fprintf (stderr
, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
338 file1
, file2
, count1
, count2
);
342 for (i
= 0; i
< count1
; i
++)
344 if (entries1
[i
].a_type
!= entries2
[i
].a_type
)
346 fprintf (stderr
, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
347 file1
, file2
, i
, entries1
[i
].a_type
, entries2
[i
].a_type
);
350 if (entries1
[i
].a_who
!= entries2
[i
].a_who
)
352 fprintf (stderr
, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
353 file1
, file2
, i
, (int)entries1
[i
].a_who
, (int)entries2
[i
].a_who
);
356 if (entries1
[i
].a_access_mask
!= entries2
[i
].a_access_mask
)
358 fprintf (stderr
, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
359 file1
, file2
, i
, (unsigned int) entries1
[i
].a_access_mask
, (unsigned int) entries2
[i
].a_access_mask
);
362 if (entries1
[i
].a_flags
!= entries2
[i
].a_flags
)
364 fprintf (stderr
, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
365 file1
, file2
, i
, (unsigned int) entries1
[i
].a_flags
, (unsigned int) entries2
[i
].a_flags
);
371 #elif HAVE_GETACL /* HP-UX */
375 count1
= getacl (file1
, 0, NULL
);
377 && (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
))
379 count2
= getacl (file2
, 0, NULL
);
381 && (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
))
386 fprintf (stderr
, "error accessing the ACLs of file %s\n", file1
);
392 fprintf (stderr
, "error accessing the ACLs of file %s\n", file2
);
396 if (count1
!= count2
)
398 fprintf (stderr
, "files %s and %s have different number of ACLs: %d and %d\n",
399 file1
, file2
, count1
, count2
);
404 struct acl_entry
*entries1
= XNMALLOC (count1
, struct acl_entry
);
405 struct acl_entry
*entries2
= XNMALLOC (count2
, struct acl_entry
);
408 if (getacl (file1
, count1
, entries1
) < count1
)
410 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file1
);
414 if (getacl (file2
, count2
, entries2
) < count1
)
416 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file2
);
420 for (i
= 0; i
< count1
; i
++)
422 if (entries1
[i
].uid
!= entries2
[i
].uid
)
424 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
425 file1
, file2
, i
, (int)entries1
[i
].uid
, (int)entries2
[i
].uid
);
428 if (entries1
[i
].gid
!= entries2
[i
].gid
)
430 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
431 file1
, file2
, i
, (int)entries1
[i
].gid
, (int)entries2
[i
].gid
);
434 if (entries1
[i
].mode
!= entries2
[i
].mode
)
436 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
437 file1
, file2
, i
, (unsigned int) entries1
[i
].mode
, (unsigned int) entries2
[i
].mode
);
443 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
445 struct acl dummy_entries
[NACLVENTRIES
];
447 count1
= acl ((char *) file1
, ACL_CNT
, NACLVENTRIES
, dummy_entries
);
449 && (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
))
451 count2
= acl ((char *) file2
, ACL_CNT
, NACLVENTRIES
, dummy_entries
);
453 && (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
))
459 fprintf (stderr
, "error accessing the ACLs of file %s\n", file1
);
465 fprintf (stderr
, "error accessing the ACLs of file %s\n", file2
);
469 if (count1
!= count2
)
471 fprintf (stderr
, "files %s and %s have different number of ACLs: %d and %d\n",
472 file1
, file2
, count1
, count2
);
477 struct acl
*entries1
= XNMALLOC (count1
, struct acl
);
478 struct acl
*entries2
= XNMALLOC (count2
, struct acl
);
481 if (acl ((char *) file1
, ACL_GET
, count1
, entries1
) < count1
)
483 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file1
);
487 if (acl ((char *) file2
, ACL_GET
, count2
, entries2
) < count1
)
489 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file2
);
493 for (i
= 0; i
< count1
; i
++)
495 if (entries1
[i
].a_type
!= entries2
[i
].a_type
)
497 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
498 file1
, file2
, i
, entries1
[i
].a_type
, entries2
[i
].a_type
);
501 if (entries1
[i
].a_id
!= entries2
[i
].a_id
)
503 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
504 file1
, file2
, i
, (int)entries1
[i
].a_id
, (int)entries2
[i
].a_id
);
507 if (entries1
[i
].a_perm
!= entries2
[i
].a_perm
)
509 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
510 file1
, file2
, i
, (unsigned int) entries1
[i
].a_perm
, (unsigned int) entries2
[i
].a_perm
);
516 #elif HAVE_ACLX_GET /* AIX */
519 size_t aclsize1
= sizeof (acl1
);
522 size_t textsize1
= sizeof (text1
);
525 size_t aclsize2
= sizeof (acl2
);
528 size_t textsize2
= sizeof (text2
);
530 /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
533 if (aclx_get (file1
, 0, &type1
, acl1
, &aclsize1
, &mode1
) < 0)
539 fprintf (stderr
, "error accessing the ACLs of file %s\n", file1
);
545 if (aclx_printStr (text1
, &textsize1
, acl1
, aclsize1
, type1
, file1
, 0) < 0)
547 fprintf (stderr
, "cannot convert the ACLs of file %s to text\n", file1
);
552 /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
555 if (aclx_get (file2
, 0, &type2
, acl2
, &aclsize2
, &mode2
) < 0)
561 fprintf (stderr
, "error accessing the ACLs of file %s\n", file2
);
567 if (aclx_printStr (text2
, &textsize2
, acl2
, aclsize2
, type2
, file2
, 0) < 0)
569 fprintf (stderr
, "cannot convert the ACLs of file %s to text\n", file2
);
574 if (strcmp (text1
, text2
) != 0)
576 fprintf (stderr
, "files %s and %s have different ACLs:\n%s\n%s\n",
577 file1
, file2
, text1
, text2
);
580 #elif HAVE_STATACL /* older AIX */
581 union { struct acl a
; char room
[4096]; } acl1
;
582 union { struct acl a
; char room
[4096]; } acl2
;
585 if (statacl (file1
, STX_NORMAL
, &acl1
.a
, sizeof (acl1
)) < 0)
587 fprintf (stderr
, "error accessing the ACLs of file %s\n", file1
);
591 if (statacl (file2
, STX_NORMAL
, &acl2
.a
, sizeof (acl2
)) < 0)
593 fprintf (stderr
, "error accessing the ACLs of file %s\n", file2
);
598 if (acl1
.a
.acl_len
!= acl2
.a
.acl_len
)
600 fprintf (stderr
, "files %s and %s have different ACL lengths: %u and %u\n",
601 file1
, file2
, acl1
.a
.acl_len
, acl2
.a
.acl_len
);
604 if (acl1
.a
.acl_mode
!= acl2
.a
.acl_mode
)
606 fprintf (stderr
, "files %s and %s have different ACL modes: %03o and %03o\n",
607 file1
, file2
, acl1
.a
.acl_mode
, acl2
.a
.acl_mode
);
610 if (acl1
.a
.u_access
!= acl2
.a
.u_access
611 || acl1
.a
.g_access
!= acl2
.a
.g_access
612 || acl1
.a
.o_access
!= acl2
.a
.o_access
)
614 fprintf (stderr
, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
616 acl1
.a
.u_access
, acl1
.a
.g_access
, acl1
.a
.o_access
,
617 acl2
.a
.u_access
, acl2
.a
.g_access
, acl2
.a
.o_access
);
620 if (memcmp (acl1
.a
.acl_ext
, acl2
.a
.acl_ext
, acl1
.a
.acl_len
) != 0)
622 fprintf (stderr
, "files %s and %s have different ACL entries\n",
626 #elif HAVE_ACLSORT /* NonStop Kernel */
630 count1
= acl ((char *) file1
, ACL_CNT
, NACLENTRIES
, NULL
);
631 count2
= acl ((char *) file2
, ACL_CNT
, NACLENTRIES
, NULL
);
635 fprintf (stderr
, "error accessing the ACLs of file %s\n", file1
);
641 fprintf (stderr
, "error accessing the ACLs of file %s\n", file2
);
645 if (count1
!= count2
)
647 fprintf (stderr
, "files %s and %s have different number of ACLs: %d and %d\n",
648 file1
, file2
, count1
, count2
);
653 struct acl
*entries1
= XNMALLOC (count1
, struct acl
);
654 struct acl
*entries2
= XNMALLOC (count2
, struct acl
);
657 if (acl ((char *) file1
, ACL_GET
, count1
, entries1
) < count1
)
659 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file1
);
663 if (acl ((char *) file2
, ACL_GET
, count2
, entries2
) < count1
)
665 fprintf (stderr
, "error retrieving the ACLs of file %s\n", file2
);
669 for (i
= 0; i
< count1
; i
++)
671 if (entries1
[i
].a_type
!= entries2
[i
].a_type
)
673 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
674 file1
, file2
, i
, entries1
[i
].a_type
, entries2
[i
].a_type
);
677 if (entries1
[i
].a_id
!= entries2
[i
].a_id
)
679 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
680 file1
, file2
, i
, (int)entries1
[i
].a_id
, (int)entries2
[i
].a_id
);
683 if (entries1
[i
].a_perm
!= entries2
[i
].a_perm
)
685 fprintf (stderr
, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
686 file1
, file2
, i
, (unsigned int) entries1
[i
].a_perm
, (unsigned int) entries2
[i
].a_perm
);