acl: Fix a test failure on AIX >= 5.3 with NFS.
[gnulib.git] / tests / test-sameacls.c
1 /* Test whether two files have the same ACLs.
2    Copyright (C) 2008-2011 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, MacOS X, IRIX, Tru64 */
119     static const int types[] =
120       {
121         ACL_TYPE_ACCESS
122 # if HAVE_ACL_TYPE_EXTENDED /* MacOS 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   count2 = acl (file2, GETACLCNT, 0, NULL);
231
232   if (count1 < 0)
233     {
234       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
235       fflush (stderr);
236       abort ();
237     }
238   if (count2 < 0)
239     {
240       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
241       fflush (stderr);
242       abort ();
243     }
244   if (count1 != count2)
245     {
246       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
247                file1, file2, count1, count2);
248       return 1;
249     }
250   else
251     {
252       aclent_t *entries1 = XNMALLOC (count1, aclent_t);
253       aclent_t *entries2 = XNMALLOC (count2, aclent_t);
254       int i;
255
256       if (acl (file1, GETACL, count1, entries1) < count1)
257         {
258           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
259           fflush (stderr);
260           abort ();
261         }
262       if (acl (file2, GETACL, count2, entries2) < count1)
263         {
264           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
265           fflush (stderr);
266           abort ();
267         }
268       for (i = 0; i < count1; i++)
269         {
270           if (entries1[i].a_type != entries2[i].a_type)
271             {
272               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
273                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
274               return 1;
275             }
276           if (entries1[i].a_id != entries2[i].a_id)
277             {
278               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
279                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
280               return 1;
281             }
282           if (entries1[i].a_perm != entries2[i].a_perm)
283             {
284               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
285                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
286               return 1;
287             }
288         }
289     }
290 # ifdef ACE_GETACL
291   count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
292   if (count1 < 0 && errno == EINVAL)
293     count1 = 0;
294   count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
295   if (count2 < 0 && errno == EINVAL)
296     count2 = 0;
297   if (count1 < 0)
298     {
299       fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
300       fflush (stderr);
301       abort ();
302     }
303   if (count2 < 0)
304     {
305       fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
306       fflush (stderr);
307       abort ();
308     }
309   if (count1 != count2)
310     {
311       fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
312                file1, file2, count1, count2);
313       return 1;
314     }
315   else if (count1 > 0)
316     {
317       ace_t *entries1 = XNMALLOC (count1, ace_t);
318       ace_t *entries2 = XNMALLOC (count2, ace_t);
319       int i;
320
321       if (acl (file1, ACE_GETACL, count1, entries1) < count1)
322         {
323           fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
324           fflush (stderr);
325           abort ();
326         }
327       if (acl (file2, ACE_GETACL, count2, entries2) < count1)
328         {
329           fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
330           fflush (stderr);
331           abort ();
332         }
333       for (i = 0; i < count1; i++)
334         {
335           if (entries1[i].a_type != entries2[i].a_type)
336             {
337               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
338                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
339               return 1;
340             }
341           if (entries1[i].a_who != entries2[i].a_who)
342             {
343               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
344                        file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who);
345               return 1;
346             }
347           if (entries1[i].a_access_mask != entries2[i].a_access_mask)
348             {
349               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
350                        file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask);
351               return 1;
352             }
353           if (entries1[i].a_flags != entries2[i].a_flags)
354             {
355               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
356                        file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags);
357               return 1;
358             }
359         }
360     }
361 # endif
362 #elif HAVE_GETACL /* HP-UX */
363   int count1;
364   int count2;
365
366   count1 = getacl (file1, 0, NULL);
367   if (count1 < 0
368       && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
369     count1 = 0;
370   count2 = getacl (file2, 0, NULL);
371   if (count2 < 0
372       && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
373     count2 = 0;
374
375   if (count1 < 0)
376     {
377       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
378       fflush (stderr);
379       abort ();
380     }
381   if (count2 < 0)
382     {
383       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
384       fflush (stderr);
385       abort ();
386     }
387   if (count1 != count2)
388     {
389       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
390                file1, file2, count1, count2);
391       return 1;
392     }
393   else if (count1 > 0)
394     {
395       struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
396       struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
397       int i;
398
399       if (getacl (file1, count1, entries1) < count1)
400         {
401           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
402           fflush (stderr);
403           abort ();
404         }
405       if (getacl (file2, count2, entries2) < count1)
406         {
407           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
408           fflush (stderr);
409           abort ();
410         }
411       for (i = 0; i < count1; i++)
412         {
413           if (entries1[i].uid != entries2[i].uid)
414             {
415               fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
416                        file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid);
417               return 1;
418             }
419           if (entries1[i].gid != entries2[i].gid)
420             {
421               fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
422                        file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid);
423               return 1;
424             }
425           if (entries1[i].mode != entries2[i].mode)
426             {
427               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
428                        file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode);
429               return 1;
430             }
431         }
432     }
433
434 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
435   {
436     struct acl dummy_entries[NACLVENTRIES];
437
438     count1 = acl ((char *) file1, ACL_CNT, NACLVENTRIES, dummy_entries);
439     if (count1 < 0
440         && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
441       count1 = 0;
442     count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries);
443     if (count2 < 0
444         && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
445       count2 = 0;
446   }
447
448   if (count1 < 0)
449     {
450       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
451       fflush (stderr);
452       abort ();
453     }
454   if (count2 < 0)
455     {
456       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
457       fflush (stderr);
458       abort ();
459     }
460   if (count1 != count2)
461     {
462       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
463                file1, file2, count1, count2);
464       return 1;
465     }
466   else if (count1 > 0)
467     {
468       struct acl *entries1 = XNMALLOC (count1, struct acl);
469       struct acl *entries2 = XNMALLOC (count2, struct acl);
470       int i;
471
472       if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
473         {
474           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
475           fflush (stderr);
476           abort ();
477         }
478       if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
479         {
480           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
481           fflush (stderr);
482           abort ();
483         }
484       for (i = 0; i < count1; i++)
485         {
486           if (entries1[i].a_type != entries2[i].a_type)
487             {
488               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
489                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
490               return 1;
491             }
492           if (entries1[i].a_id != entries2[i].a_id)
493             {
494               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
495                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
496               return 1;
497             }
498           if (entries1[i].a_perm != entries2[i].a_perm)
499             {
500               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
501                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
502               return 1;
503             }
504         }
505     }
506 # endif
507 #elif HAVE_ACLX_GET /* AIX */
508   acl_type_t type1;
509   char acl1[1000];
510   size_t aclsize1 = sizeof (acl1);
511   mode_t mode1;
512   char text1[1000];
513   size_t textsize1 = sizeof (text1);
514   acl_type_t type2;
515   char acl2[1000];
516   size_t aclsize2 = sizeof (acl2);
517   mode_t mode2;
518   char text2[1000];
519   size_t textsize2 = sizeof (text2);
520
521   /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
522      true, in AIX 5.3.  */
523   type1.u64 = ACL_ANY;
524   if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
525     {
526       if (errno == ENOSYS)
527         text1[0] = '\0';
528       else
529         {
530           fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
531           fflush (stderr);
532           abort ();
533         }
534     }
535   else
536     if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0)
537       {
538         fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
539         fflush (stderr);
540         abort ();
541       }
542
543   /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
544      true, in AIX 5.3.  */
545   type2.u64 = ACL_ANY;
546   if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
547     {
548       if (errno == ENOSYS)
549         text2[0] = '\0';
550       else
551         {
552           fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
553           fflush (stderr);
554           abort ();
555         }
556     }
557   else
558     if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0)
559       {
560         fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
561         fflush (stderr);
562         abort ();
563       }
564
565   if (strcmp (text1, text2) != 0)
566     {
567       fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
568                file1, file2, text1, text2);
569       return 1;
570     }
571 #elif HAVE_STATACL /* older AIX */
572   union { struct acl a; char room[4096]; } acl1;
573   union { struct acl a; char room[4096]; } acl2;
574   unsigned int i;
575
576   if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
577     {
578       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
579       fflush (stderr);
580       abort ();
581     }
582   if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
583     {
584       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
585       fflush (stderr);
586       abort ();
587     }
588
589   if (acl1.a.acl_len != acl2.a.acl_len)
590     {
591       fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
592                file1, file2, acl1.a.acl_len, acl2.a.acl_len);
593       return 1;
594     }
595   if (acl1.a.acl_mode != acl2.a.acl_mode)
596     {
597       fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
598                file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
599       return 1;
600     }
601   if (acl1.a.u_access != acl2.a.u_access
602       || acl1.a.g_access != acl2.a.g_access
603       || acl1.a.o_access != acl2.a.o_access)
604     {
605       fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
606                file1, file2,
607                acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
608                acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
609       return 1;
610     }
611   if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
612     {
613       fprintf (stderr, "files %s and %s have different ACL entries\n",
614                file1, file2);
615       return 1;
616     }
617 #elif HAVE_ACLSORT /* NonStop Kernel */
618   int count1;
619   int count2;
620
621   count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
622   count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);
623
624   if (count1 < 0)
625     {
626       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
627       fflush (stderr);
628       abort ();
629     }
630   if (count2 < 0)
631     {
632       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
633       fflush (stderr);
634       abort ();
635     }
636   if (count1 != count2)
637     {
638       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
639                file1, file2, count1, count2);
640       return 1;
641     }
642   else if (count1 > 0)
643     {
644       struct acl *entries1 = XNMALLOC (count1, struct acl);
645       struct acl *entries2 = XNMALLOC (count2, struct acl);
646       int i;
647
648       if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
649         {
650           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
651           fflush (stderr);
652           abort ();
653         }
654       if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
655         {
656           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
657           fflush (stderr);
658           abort ();
659         }
660       for (i = 0; i < count1; i++)
661         {
662           if (entries1[i].a_type != entries2[i].a_type)
663             {
664               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
665                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
666               return 1;
667             }
668           if (entries1[i].a_id != entries2[i].a_id)
669             {
670               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
671                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
672               return 1;
673             }
674           if (entries1[i].a_perm != entries2[i].a_perm)
675             {
676               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
677                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
678               return 1;
679             }
680         }
681     }
682 #endif
683   }
684
685   return 0;
686 }