maint: update copyright
[gnulib.git] / tests / test-sameacls.c
1 /* Test whether two files have the same ACLs.
2    Copyright (C) 2008-2014 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2008.  */
18
19 #include <config.h>
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26
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
35
36 #include "progname.h"
37 #include "read-file.h"
38 #include "xalloc.h"
39 #include "macros.h"
40
41 int
42 main (int argc, char *argv[])
43 {
44   const char *file1;
45   const char *file2;
46
47   set_program_name (argv[0]);
48
49   ASSERT (argc == 3);
50
51   file1 = argv[1];
52   file2 = argv[2];
53
54   /* Compare the contents of the two files.  */
55   {
56     size_t size1;
57     char *contents1;
58     size_t size2;
59     char *contents2;
60
61     contents1 = read_file (file1, &size1);
62     if (contents1 == NULL)
63       {
64         fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
65         fflush (stderr);
66         abort ();
67       }
68     contents2 = read_file (file2, &size2);
69     if (contents2 == NULL)
70       {
71         fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
72         fflush (stderr);
73         abort ();
74       }
75
76     if (size2 != size1)
77       {
78         fprintf (stderr, "files %s and %s have different sizes\n",
79                  file1, file2);
80         fflush (stderr);
81         abort ();
82       }
83     if (memcmp (contents1, contents2, size1) != 0)
84       {
85         fprintf (stderr, "files %s and %s have different contents\n",
86                  file1, file2);
87         fflush (stderr);
88         abort ();
89       }
90   }
91
92   /* Compare the access permissions of the two files, including ACLs.  */
93   {
94     struct stat statbuf1;
95     struct stat statbuf2;
96
97     if (stat (file1, &statbuf1) < 0)
98       {
99         fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
100         fflush (stderr);
101         abort ();
102       }
103     if (stat (file2, &statbuf2) < 0)
104       {
105         fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
106         fflush (stderr);
107         abort ();
108       }
109     if (statbuf1.st_mode != statbuf2.st_mode)
110       {
111         fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
112                  file1, file2,
113                 (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
114         return 1;
115       }
116   }
117   {
118 #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
119     static const int types[] =
120       {
121         ACL_TYPE_ACCESS
122 # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
123         , ACL_TYPE_EXTENDED
124 # endif
125       };
126     int t;
127
128     for (t = 0; t < sizeof (types) / sizeof (types[0]); t++)
129       {
130         int type = types[t];
131         acl_t acl1;
132         char *text1;
133         int errno1;
134         acl_t acl2;
135         char *text2;
136         int errno2;
137
138         acl1 = acl_get_file (file1, type);
139         if (acl1 == (acl_t)NULL)
140           {
141             text1 = NULL;
142             errno1 = errno;
143           }
144         else
145           {
146             text1 = acl_to_text (acl1, NULL);
147             if (text1 == NULL)
148               errno1 = errno;
149             else
150               errno1 = 0;
151           }
152         acl2 = acl_get_file (file2, type);
153         if (acl2 == (acl_t)NULL)
154           {
155             text2 = NULL;
156             errno2 = errno;
157           }
158         else
159           {
160             text2 = acl_to_text (acl2, NULL);
161             if (text2 == NULL)
162               errno2 = errno;
163             else
164               errno2 = 0;
165           }
166
167         if (acl1 != (acl_t)NULL)
168           {
169             if (acl2 != (acl_t)NULL)
170               {
171                 if (text1 != NULL)
172                   {
173                     if (text2 != NULL)
174                       {
175                         if (strcmp (text1, text2) != 0)
176                           {
177                             fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
178                                      file1, file2, text1, text2);
179                             return 1;
180                           }
181                       }
182                     else
183                       {
184                         fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
185                                  file1, file2);
186                         return 1;
187                       }
188                   }
189                 else
190                   {
191                     if (text2 != NULL)
192                       {
193                         fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
194                                  file1, file2);
195                         return 1;
196                       }
197                     else
198                       {
199                         if (errno1 != errno2)
200                           {
201                             fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
202                                      file1, file2, errno1, errno2);
203                             return 1;
204                           }
205                       }
206                   }
207               }
208             else
209               {
210                 fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
211                          file1, file2);
212                 return 1;
213               }
214           }
215         else
216           {
217             if (acl2 != (acl_t)NULL)
218               {
219                 fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
220                          file1, file2);
221                 return 1;
222               }
223           }
224       }
225 #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
226   int count1;
227   int count2;
228
229   count1 = acl (file1, GETACLCNT, 0, NULL);
230   if (count1 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
231     count1 = 0;
232   count2 = acl (file2, GETACLCNT, 0, NULL);
233   if (count2 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
234     count2 = 0;
235
236   if (count1 < 0)
237     {
238       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
239       fflush (stderr);
240       abort ();
241     }
242   if (count2 < 0)
243     {
244       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
245       fflush (stderr);
246       abort ();
247     }
248   if (count1 != count2)
249     {
250       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
251                file1, file2, count1, count2);
252       return 1;
253     }
254   else
255     {
256       aclent_t *entries1 = XNMALLOC (count1, aclent_t);
257       aclent_t *entries2 = XNMALLOC (count2, aclent_t);
258       int i;
259
260       if (count1 > 0 && acl (file1, GETACL, count1, entries1) < count1)
261         {
262           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
263           fflush (stderr);
264           abort ();
265         }
266       if (count2 > 0 && acl (file2, GETACL, count2, entries2) < count1)
267         {
268           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
269           fflush (stderr);
270           abort ();
271         }
272       for (i = 0; i < count1; i++)
273         {
274           if (entries1[i].a_type != entries2[i].a_type)
275             {
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);
278               return 1;
279             }
280           if (entries1[i].a_id != entries2[i].a_id)
281             {
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);
284               return 1;
285             }
286           if (entries1[i].a_perm != entries2[i].a_perm)
287             {
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);
290               return 1;
291             }
292         }
293     }
294 # ifdef ACE_GETACL
295   count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
296   if (count1 < 0 && errno == EINVAL)
297     count1 = 0;
298   count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
299   if (count2 < 0 && errno == EINVAL)
300     count2 = 0;
301   if (count1 < 0)
302     {
303       fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
304       fflush (stderr);
305       abort ();
306     }
307   if (count2 < 0)
308     {
309       fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
310       fflush (stderr);
311       abort ();
312     }
313   {
314     ace_t *entries1 = XNMALLOC (count1, ace_t);
315     ace_t *entries2 = XNMALLOC (count2, ace_t);
316     int ret;
317     int i;
318
319     ret = acl (file1, ACE_GETACL, count1, entries1);
320     if (ret < 0 && errno == EINVAL)
321       count1 = 0;
322     else if (ret < count1)
323       {
324         fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
325         fflush (stderr);
326         abort ();
327       }
328     ret = acl (file2, ACE_GETACL, count2, entries2);
329     if (ret < 0 && errno == EINVAL)
330       count2 = 0;
331     else if (ret < count2)
332       {
333         fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
334         fflush (stderr);
335         abort ();
336       }
337
338     if (count1 != count2)
339       {
340         fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
341                  file1, file2, count1, count2);
342         return 1;
343       }
344
345     for (i = 0; i < count1; i++)
346       {
347         if (entries1[i].a_type != entries2[i].a_type)
348           {
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);
351             return 1;
352           }
353         if (entries1[i].a_who != entries2[i].a_who)
354           {
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);
357             return 1;
358           }
359         if (entries1[i].a_access_mask != entries2[i].a_access_mask)
360           {
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);
363             return 1;
364           }
365         if (entries1[i].a_flags != entries2[i].a_flags)
366           {
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);
369             return 1;
370           }
371       }
372   }
373 # endif
374 #elif HAVE_GETACL /* HP-UX */
375   int count1;
376   int count2;
377
378   count1 = getacl (file1, 0, NULL);
379   if (count1 < 0
380       && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
381     count1 = 0;
382   count2 = getacl (file2, 0, NULL);
383   if (count2 < 0
384       && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
385     count2 = 0;
386
387   if (count1 < 0)
388     {
389       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
390       fflush (stderr);
391       abort ();
392     }
393   if (count2 < 0)
394     {
395       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
396       fflush (stderr);
397       abort ();
398     }
399   if (count1 != count2)
400     {
401       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
402                file1, file2, count1, count2);
403       return 1;
404     }
405   else if (count1 > 0)
406     {
407       struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
408       struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
409       int i;
410
411       if (getacl (file1, count1, entries1) < count1)
412         {
413           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
414           fflush (stderr);
415           abort ();
416         }
417       if (getacl (file2, count2, entries2) < count1)
418         {
419           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
420           fflush (stderr);
421           abort ();
422         }
423       for (i = 0; i < count1; i++)
424         {
425           if (entries1[i].uid != entries2[i].uid)
426             {
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);
429               return 1;
430             }
431           if (entries1[i].gid != entries2[i].gid)
432             {
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);
435               return 1;
436             }
437           if (entries1[i].mode != entries2[i].mode)
438             {
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);
441               return 1;
442             }
443         }
444     }
445
446 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
447   {
448     struct acl dummy_entries[NACLVENTRIES];
449
450     count1 = acl ((char *) file1, ACL_CNT, NACLVENTRIES, dummy_entries);
451     if (count1 < 0
452         && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
453       count1 = 0;
454     count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries);
455     if (count2 < 0
456         && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
457       count2 = 0;
458   }
459
460   if (count1 < 0)
461     {
462       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
463       fflush (stderr);
464       abort ();
465     }
466   if (count2 < 0)
467     {
468       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
469       fflush (stderr);
470       abort ();
471     }
472   if (count1 != count2)
473     {
474       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
475                file1, file2, count1, count2);
476       return 1;
477     }
478   else if (count1 > 0)
479     {
480       struct acl *entries1 = XNMALLOC (count1, struct acl);
481       struct acl *entries2 = XNMALLOC (count2, struct acl);
482       int i;
483
484       if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
485         {
486           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
487           fflush (stderr);
488           abort ();
489         }
490       if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
491         {
492           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
493           fflush (stderr);
494           abort ();
495         }
496       for (i = 0; i < count1; i++)
497         {
498           if (entries1[i].a_type != entries2[i].a_type)
499             {
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);
502               return 1;
503             }
504           if (entries1[i].a_id != entries2[i].a_id)
505             {
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);
508               return 1;
509             }
510           if (entries1[i].a_perm != entries2[i].a_perm)
511             {
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);
514               return 1;
515             }
516         }
517     }
518 # endif
519 #elif HAVE_ACLX_GET /* AIX */
520   acl_type_t type1;
521   char acl1[1000];
522   size_t aclsize1 = sizeof (acl1);
523   mode_t mode1;
524   char text1[1000];
525   size_t textsize1 = sizeof (text1);
526   acl_type_t type2;
527   char acl2[1000];
528   size_t aclsize2 = sizeof (acl2);
529   mode_t mode2;
530   char text2[1000];
531   size_t textsize2 = sizeof (text2);
532
533   /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
534      true, in AIX 5.3.  */
535   type1.u64 = ACL_ANY;
536   if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
537     {
538       if (errno == ENOSYS)
539         text1[0] = '\0';
540       else
541         {
542           fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
543           fflush (stderr);
544           abort ();
545         }
546     }
547   else
548     if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0)
549       {
550         fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
551         fflush (stderr);
552         abort ();
553       }
554
555   /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
556      true, in AIX 5.3.  */
557   type2.u64 = ACL_ANY;
558   if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
559     {
560       if (errno == ENOSYS)
561         text2[0] = '\0';
562       else
563         {
564           fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
565           fflush (stderr);
566           abort ();
567         }
568     }
569   else
570     if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0)
571       {
572         fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
573         fflush (stderr);
574         abort ();
575       }
576
577   if (strcmp (text1, text2) != 0)
578     {
579       fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
580                file1, file2, text1, text2);
581       return 1;
582     }
583 #elif HAVE_STATACL /* older AIX */
584   union { struct acl a; char room[4096]; } acl1;
585   union { struct acl a; char room[4096]; } acl2;
586   unsigned int i;
587
588   if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
589     {
590       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
591       fflush (stderr);
592       abort ();
593     }
594   if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
595     {
596       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
597       fflush (stderr);
598       abort ();
599     }
600
601   if (acl1.a.acl_len != acl2.a.acl_len)
602     {
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);
605       return 1;
606     }
607   if (acl1.a.acl_mode != acl2.a.acl_mode)
608     {
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);
611       return 1;
612     }
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)
616     {
617       fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
618                file1, file2,
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);
621       return 1;
622     }
623   if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
624     {
625       fprintf (stderr, "files %s and %s have different ACL entries\n",
626                file1, file2);
627       return 1;
628     }
629 #elif HAVE_ACLSORT /* NonStop Kernel */
630   int count1;
631   int count2;
632
633   count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
634   count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);
635
636   if (count1 < 0)
637     {
638       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
639       fflush (stderr);
640       abort ();
641     }
642   if (count2 < 0)
643     {
644       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
645       fflush (stderr);
646       abort ();
647     }
648   if (count1 != count2)
649     {
650       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
651                file1, file2, count1, count2);
652       return 1;
653     }
654   else if (count1 > 0)
655     {
656       struct acl *entries1 = XNMALLOC (count1, struct acl);
657       struct acl *entries2 = XNMALLOC (count2, struct acl);
658       int i;
659
660       if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
661         {
662           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
663           fflush (stderr);
664           abort ();
665         }
666       if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
667         {
668           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
669           fflush (stderr);
670           abort ();
671         }
672       for (i = 0; i < count1; i++)
673         {
674           if (entries1[i].a_type != entries2[i].a_type)
675             {
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);
678               return 1;
679             }
680           if (entries1[i].a_id != entries2[i].a_id)
681             {
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);
684               return 1;
685             }
686           if (entries1[i].a_perm != entries2[i].a_perm)
687             {
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);
690               return 1;
691             }
692         }
693     }
694 #endif
695   }
696
697   return 0;
698 }