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