backupfile: Fix module dependencies.
[gnulib.git] / tests / test-sameacls.c
blob228c16bc359028b4920f96bbd55ddb59fefc9d62
1 /* Test whether two files have the same ACLs.
2 Copyright (C) 2008-2019 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 <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2008. */
19 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
27 #if HAVE_ACL_GET_FILE || HAVE_FACL || HAVE_GETACL || HAVE_ACLX_GET || HAVE_STATACL || HAVE_ACLSORT
28 # include <sys/types.h>
29 # include <sys/acl.h>
30 #endif
31 #if HAVE_ACLV_H
32 # include <sys/types.h>
33 # include <aclv.h>
34 #endif
36 #include "read-file.h"
37 #include "xalloc.h"
38 #include "macros.h"
40 int
41 main (int argc, char *argv[])
43 const char *file1;
44 const char *file2;
46 ASSERT (argc == 3);
48 file1 = argv[1];
49 file2 = argv[2];
51 /* Compare the contents of the two files. */
53 size_t size1;
54 char *contents1;
55 size_t size2;
56 char *contents2;
58 contents1 = read_file (file1, &size1);
59 if (contents1 == NULL)
61 fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
62 fflush (stderr);
63 abort ();
65 contents2 = read_file (file2, &size2);
66 if (contents2 == NULL)
68 fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
69 fflush (stderr);
70 abort ();
73 if (size2 != size1)
75 fprintf (stderr, "files %s and %s have different sizes\n",
76 file1, file2);
77 fflush (stderr);
78 abort ();
80 if (memcmp (contents1, contents2, size1) != 0)
82 fprintf (stderr, "files %s and %s have different contents\n",
83 file1, file2);
84 fflush (stderr);
85 abort ();
89 /* Compare the access permissions of the two files, including ACLs. */
91 struct stat statbuf1;
92 struct stat statbuf2;
94 if (stat (file1, &statbuf1) < 0)
96 fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
97 fflush (stderr);
98 abort ();
100 if (stat (file2, &statbuf2) < 0)
102 fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
103 fflush (stderr);
104 abort ();
106 if (statbuf1.st_mode != statbuf2.st_mode)
108 fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
109 file1, file2,
110 (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
111 return 1;
115 #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
116 static const int types[] =
118 ACL_TYPE_ACCESS
119 # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
120 , ACL_TYPE_EXTENDED
121 # endif
123 int t;
125 for (t = 0; t < sizeof (types) / sizeof (types[0]); t++)
127 int type = types[t];
128 acl_t acl1;
129 char *text1;
130 int errno1;
131 acl_t acl2;
132 char *text2;
133 int errno2;
135 acl1 = acl_get_file (file1, type);
136 if (acl1 == (acl_t)NULL)
138 text1 = NULL;
139 errno1 = errno;
141 else
143 text1 = acl_to_text (acl1, NULL);
144 if (text1 == NULL)
145 errno1 = errno;
146 else
147 errno1 = 0;
149 acl2 = acl_get_file (file2, type);
150 if (acl2 == (acl_t)NULL)
152 text2 = NULL;
153 errno2 = errno;
155 else
157 text2 = acl_to_text (acl2, NULL);
158 if (text2 == NULL)
159 errno2 = errno;
160 else
161 errno2 = 0;
164 if (acl1 != (acl_t)NULL)
166 if (acl2 != (acl_t)NULL)
168 if (text1 != NULL)
170 if (text2 != 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);
176 return 1;
179 else
181 fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
182 file1, file2);
183 return 1;
186 else
188 if (text2 != NULL)
190 fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
191 file1, file2);
192 return 1;
194 else
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);
200 return 1;
205 else
207 fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
208 file1, file2);
209 return 1;
212 else
214 if (acl2 != (acl_t)NULL)
216 fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
217 file1, file2);
218 return 1;
222 #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
223 int count1;
224 int count2;
226 count1 = acl (file1, GETACLCNT, 0, NULL);
227 if (count1 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
228 count1 = 0;
229 count2 = acl (file2, GETACLCNT, 0, NULL);
230 if (count2 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
231 count2 = 0;
233 if (count1 < 0)
235 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
236 fflush (stderr);
237 abort ();
239 if (count2 < 0)
241 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
242 fflush (stderr);
243 abort ();
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);
249 return 1;
251 else
253 aclent_t *entries1 = XNMALLOC (count1, aclent_t);
254 aclent_t *entries2 = XNMALLOC (count2, aclent_t);
255 int i;
257 if (count1 > 0 && acl (file1, GETACL, count1, entries1) < count1)
259 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
260 fflush (stderr);
261 abort ();
263 if (count2 > 0 && acl (file2, GETACL, count2, entries2) < count1)
265 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
266 fflush (stderr);
267 abort ();
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);
275 return 1;
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);
281 return 1;
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);
287 return 1;
291 # ifdef ACE_GETACL
292 count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
293 if (count1 < 0 && errno == EINVAL)
294 count1 = 0;
295 count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
296 if (count2 < 0 && errno == EINVAL)
297 count2 = 0;
298 if (count1 < 0)
300 fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
301 fflush (stderr);
302 abort ();
304 if (count2 < 0)
306 fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
307 fflush (stderr);
308 abort ();
311 ace_t *entries1 = XNMALLOC (count1, ace_t);
312 ace_t *entries2 = XNMALLOC (count2, ace_t);
313 int ret;
314 int i;
316 ret = acl (file1, ACE_GETACL, count1, entries1);
317 if (ret < 0 && errno == EINVAL)
318 count1 = 0;
319 else if (ret < count1)
321 fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
322 fflush (stderr);
323 abort ();
325 ret = acl (file2, ACE_GETACL, count2, entries2);
326 if (ret < 0 && errno == EINVAL)
327 count2 = 0;
328 else if (ret < count2)
330 fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
331 fflush (stderr);
332 abort ();
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);
339 return 1;
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);
348 return 1;
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);
354 return 1;
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);
360 return 1;
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);
366 return 1;
370 # endif
371 #elif HAVE_GETACL /* HP-UX */
372 int count1;
373 int count2;
375 count1 = getacl (file1, 0, NULL);
376 if (count1 < 0
377 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
378 count1 = 0;
379 count2 = getacl (file2, 0, NULL);
380 if (count2 < 0
381 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
382 count2 = 0;
384 if (count1 < 0)
386 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
387 fflush (stderr);
388 abort ();
390 if (count2 < 0)
392 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
393 fflush (stderr);
394 abort ();
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);
400 return 1;
402 else if (count1 > 0)
404 struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
405 struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
406 int i;
408 if (getacl (file1, count1, entries1) < count1)
410 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
411 fflush (stderr);
412 abort ();
414 if (getacl (file2, count2, entries2) < count1)
416 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
417 fflush (stderr);
418 abort ();
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);
426 return 1;
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);
432 return 1;
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);
438 return 1;
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);
448 if (count1 < 0
449 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
450 count1 = 0;
451 count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries);
452 if (count2 < 0
453 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
454 count2 = 0;
457 if (count1 < 0)
459 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
460 fflush (stderr);
461 abort ();
463 if (count2 < 0)
465 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
466 fflush (stderr);
467 abort ();
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);
473 return 1;
475 else if (count1 > 0)
477 struct acl *entries1 = XNMALLOC (count1, struct acl);
478 struct acl *entries2 = XNMALLOC (count2, struct acl);
479 int i;
481 if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
483 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
484 fflush (stderr);
485 abort ();
487 if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
489 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
490 fflush (stderr);
491 abort ();
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);
499 return 1;
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);
505 return 1;
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);
511 return 1;
515 # endif
516 #elif HAVE_ACLX_GET /* AIX */
517 acl_type_t type1;
518 char acl1[1000];
519 size_t aclsize1 = sizeof (acl1);
520 mode_t mode1;
521 char text1[1000];
522 size_t textsize1 = sizeof (text1);
523 acl_type_t type2;
524 char acl2[1000];
525 size_t aclsize2 = sizeof (acl2);
526 mode_t mode2;
527 char text2[1000];
528 size_t textsize2 = sizeof (text2);
530 /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
531 true, in AIX 5.3. */
532 type1.u64 = ACL_ANY;
533 if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
535 if (errno == ENOSYS)
536 text1[0] = '\0';
537 else
539 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
540 fflush (stderr);
541 abort ();
544 else
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);
548 fflush (stderr);
549 abort ();
552 /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
553 true, in AIX 5.3. */
554 type2.u64 = ACL_ANY;
555 if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
557 if (errno == ENOSYS)
558 text2[0] = '\0';
559 else
561 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
562 fflush (stderr);
563 abort ();
566 else
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);
570 fflush (stderr);
571 abort ();
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);
578 return 1;
580 #elif HAVE_STATACL /* older AIX */
581 union { struct acl a; char room[4096]; } acl1;
582 union { struct acl a; char room[4096]; } acl2;
583 unsigned int i;
585 if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
587 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
588 fflush (stderr);
589 abort ();
591 if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
593 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
594 fflush (stderr);
595 abort ();
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);
602 return 1;
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);
608 return 1;
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",
615 file1, file2,
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);
618 return 1;
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",
623 file1, file2);
624 return 1;
626 #elif HAVE_ACLSORT /* NonStop Kernel */
627 int count1;
628 int count2;
630 count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
631 count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);
633 if (count1 < 0)
635 fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
636 fflush (stderr);
637 abort ();
639 if (count2 < 0)
641 fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
642 fflush (stderr);
643 abort ();
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);
649 return 1;
651 else if (count1 > 0)
653 struct acl *entries1 = XNMALLOC (count1, struct acl);
654 struct acl *entries2 = XNMALLOC (count2, struct acl);
655 int i;
657 if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
659 fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
660 fflush (stderr);
661 abort ();
663 if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
665 fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
666 fflush (stderr);
667 abort ();
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);
675 return 1;
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);
681 return 1;
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);
687 return 1;
691 #endif
694 return 0;