1 /* Test whether two files have the same ACLs.
2 Copyright (C) 2008-2015 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>
37 #include "read-file.h"
42 main (int argc, char *argv[])
47 set_program_name (argv[0]);
54 /* Compare the contents of the two files. */
61 contents1 = read_file (file1, &size1);
62 if (contents1 == NULL)
64 fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
68 contents2 = read_file (file2, &size2);
69 if (contents2 == NULL)
71 fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
78 fprintf (stderr, "files %s and %s have different sizes\n",
83 if (memcmp (contents1, contents2, size1) != 0)
85 fprintf (stderr, "files %s and %s have different contents\n",
92 /* Compare the access permissions of the two files, including ACLs. */
97 if (stat (file1, &statbuf1) < 0)
99 fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
103 if (stat (file2, &statbuf2) < 0)
105 fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
109 if (statbuf1.st_mode != statbuf2.st_mode)
111 fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
113 (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
118 #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
119 static const int types[] =
122 # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
128 for (t = 0; t < sizeof (types) / sizeof (types[0]); t++)
138 acl1 = acl_get_file (file1, type);
139 if (acl1 == (acl_t)NULL)
146 text1 = acl_to_text (acl1, NULL);
152 acl2 = acl_get_file (file2, type);
153 if (acl2 == (acl_t)NULL)
160 text2 = acl_to_text (acl2, NULL);
167 if (acl1 != (acl_t)NULL)
169 if (acl2 != (acl_t)NULL)
175 if (strcmp (text1, text2) != 0)
177 fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
178 file1, file2, text1, text2);
184 fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
193 fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
199 if (errno1 != errno2)
201 fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
202 file1, file2, errno1, errno2);
210 fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
217 if (acl2 != (acl_t)NULL)
219 fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
225 #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
229 count1 = acl (file1, GETACLCNT, 0, NULL);
230 if (count1 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
232 count2 = acl (file2, GETACLCNT, 0, NULL);
233 if (count2 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
238 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
244 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
248 if (count1 != count2)
250 fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
251 file1, file2, count1, count2);
256 aclent_t *entries1 = XNMALLOC (count1, aclent_t);
257 aclent_t *entries2 = XNMALLOC (count2, aclent_t);
260 if (count1 > 0 && acl (file1, GETACL, count1, entries1) < count1)
262 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
266 if (count2 > 0 && acl (file2, GETACL, count2, entries2) < count1)
268 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
272 for (i = 0; i < count1; i++)
274 if (entries1[i].a_type != entries2[i].a_type)
276 fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
277 file1, file2, i, entries1[i].a_type, entries2[i].a_type);
280 if (entries1[i].a_id != entries2[i].a_id)
282 fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
283 file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
286 if (entries1[i].a_perm != entries2[i].a_perm)
288 fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
289 file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
295 count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
296 if (count1 < 0 && errno == EINVAL)
298 count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
299 if (count2 < 0 && errno == EINVAL)
303 fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
309 fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
314 ace_t *entries1 = XNMALLOC (count1, ace_t);
315 ace_t *entries2 = XNMALLOC (count2, ace_t);
319 ret = acl (file1, ACE_GETACL, count1, entries1);
320 if (ret < 0 && errno == EINVAL)
322 else if (ret < count1)
324 fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
328 ret = acl (file2, ACE_GETACL, count2, entries2);
329 if (ret < 0 && errno == EINVAL)
331 else if (ret < count2)
333 fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
338 if (count1 != count2)
340 fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
341 file1, file2, count1, count2);
345 for (i = 0; i < count1; i++)
347 if (entries1[i].a_type != entries2[i].a_type)
349 fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
350 file1, file2, i, entries1[i].a_type, entries2[i].a_type);
353 if (entries1[i].a_who != entries2[i].a_who)
355 fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
356 file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who);
359 if (entries1[i].a_access_mask != entries2[i].a_access_mask)
361 fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
362 file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask);
365 if (entries1[i].a_flags != entries2[i].a_flags)
367 fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
368 file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags);
374 #elif HAVE_GETACL /* HP-UX */
378 count1 = getacl (file1, 0, NULL);
380 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
382 count2 = getacl (file2, 0, NULL);
384 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
389 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
395 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
399 if (count1 != count2)
401 fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
402 file1, file2, count1, count2);
407 struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
408 struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
411 if (getacl (file1, count1, entries1) < count1)
413 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
417 if (getacl (file2, count2, entries2) < count1)
419 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
423 for (i = 0; i < count1; i++)
425 if (entries1[i].uid != entries2[i].uid)
427 fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
428 file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid);
431 if (entries1[i].gid != entries2[i].gid)
433 fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
434 file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid);
437 if (entries1[i].mode != entries2[i].mode)
439 fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
440 file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode);
446 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
448 struct acl dummy_entries[NACLVENTRIES];
450 count1 = acl ((char *) file1, ACL_CNT, NACLVENTRIES, dummy_entries);
452 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
454 count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries);
456 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
462 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
468 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
472 if (count1 != count2)
474 fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
475 file1, file2, count1, count2);
480 struct acl *entries1 = XNMALLOC (count1, struct acl);
481 struct acl *entries2 = XNMALLOC (count2, struct acl);
484 if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
486 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
490 if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
492 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
496 for (i = 0; i < count1; i++)
498 if (entries1[i].a_type != entries2[i].a_type)
500 fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
501 file1, file2, i, entries1[i].a_type, entries2[i].a_type);
504 if (entries1[i].a_id != entries2[i].a_id)
506 fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
507 file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
510 if (entries1[i].a_perm != entries2[i].a_perm)
512 fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
513 file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
519 #elif HAVE_ACLX_GET /* AIX */
522 size_t aclsize1 = sizeof (acl1);
525 size_t textsize1 = sizeof (text1);
528 size_t aclsize2 = sizeof (acl2);
531 size_t textsize2 = sizeof (text2);
533 /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
536 if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
542 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
548 if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0)
550 fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
555 /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
558 if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
564 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
570 if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0)
572 fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
577 if (strcmp (text1, text2) != 0)
579 fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
580 file1, file2, text1, text2);
583 #elif HAVE_STATACL /* older AIX */
584 union { struct acl a; char room[4096]; } acl1;
585 union { struct acl a; char room[4096]; } acl2;
588 if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
590 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
594 if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
596 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
601 if (acl1.a.acl_len != acl2.a.acl_len)
603 fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
604 file1, file2, acl1.a.acl_len, acl2.a.acl_len);
607 if (acl1.a.acl_mode != acl2.a.acl_mode)
609 fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
610 file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
613 if (acl1.a.u_access != acl2.a.u_access
614 || acl1.a.g_access != acl2.a.g_access
615 || acl1.a.o_access != acl2.a.o_access)
617 fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
619 acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
620 acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
623 if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
625 fprintf (stderr, "files %s and %s have different ACL entries\n",
629 #elif HAVE_ACLSORT /* NonStop Kernel */
633 count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
634 count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);
638 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
644 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
648 if (count1 != count2)
650 fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
651 file1, file2, count1, count2);
656 struct acl *entries1 = XNMALLOC (count1, struct acl);
657 struct acl *entries2 = XNMALLOC (count2, struct acl);
660 if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
662 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
666 if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
668 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
672 for (i = 0; i < count1; i++)
674 if (entries1[i].a_type != entries2[i].a_type)
676 fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
677 file1, file2, i, entries1[i].a_type, entries2[i].a_type);
680 if (entries1[i].a_id != entries2[i].a_id)
682 fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
683 file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
686 if (entries1[i].a_perm != entries2[i].a_perm)
688 fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
689 file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);