* lib/xalloc.h (DEFAULT_MXFAST): Track 64-bit glibc.
[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       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
527       fflush (stderr);
528       abort ();
529     }
530   if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0)
531     {
532       fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
533       fflush (stderr);
534       abort ();
535     }
536
537   /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
538      true, in AIX 5.3.  */
539   type2.u64 = ACL_ANY;
540   if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
541     {
542       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
543       fflush (stderr);
544       abort ();
545     }
546   if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0)
547     {
548       fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
549       fflush (stderr);
550       abort ();
551     }
552
553   if (strcmp (text1, text2) != 0)
554     {
555       fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
556                file1, file2, text1, text2);
557       return 1;
558     }
559 #elif HAVE_STATACL /* older AIX */
560   union { struct acl a; char room[4096]; } acl1;
561   union { struct acl a; char room[4096]; } acl2;
562   unsigned int i;
563
564   if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
565     {
566       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
567       fflush (stderr);
568       abort ();
569     }
570   if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
571     {
572       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
573       fflush (stderr);
574       abort ();
575     }
576
577   if (acl1.a.acl_len != acl2.a.acl_len)
578     {
579       fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
580                file1, file2, acl1.a.acl_len, acl2.a.acl_len);
581       return 1;
582     }
583   if (acl1.a.acl_mode != acl2.a.acl_mode)
584     {
585       fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
586                file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
587       return 1;
588     }
589   if (acl1.a.u_access != acl2.a.u_access
590       || acl1.a.g_access != acl2.a.g_access
591       || acl1.a.o_access != acl2.a.o_access)
592     {
593       fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
594                file1, file2,
595                acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
596                acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
597       return 1;
598     }
599   if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
600     {
601       fprintf (stderr, "files %s and %s have different ACL entries\n",
602                file1, file2);
603       return 1;
604     }
605 #elif HAVE_ACLSORT /* NonStop Kernel */
606   int count1;
607   int count2;
608
609   count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
610   count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);
611
612   if (count1 < 0)
613     {
614       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
615       fflush (stderr);
616       abort ();
617     }
618   if (count2 < 0)
619     {
620       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
621       fflush (stderr);
622       abort ();
623     }
624   if (count1 != count2)
625     {
626       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
627                file1, file2, count1, count2);
628       return 1;
629     }
630   else if (count1 > 0)
631     {
632       struct acl *entries1 = XNMALLOC (count1, struct acl);
633       struct acl *entries2 = XNMALLOC (count2, struct acl);
634       int i;
635
636       if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
637         {
638           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
639           fflush (stderr);
640           abort ();
641         }
642       if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
643         {
644           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
645           fflush (stderr);
646           abort ();
647         }
648       for (i = 0; i < count1; i++)
649         {
650           if (entries1[i].a_type != entries2[i].a_type)
651             {
652               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
653                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
654               return 1;
655             }
656           if (entries1[i].a_id != entries2[i].a_id)
657             {
658               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
659                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
660               return 1;
661             }
662           if (entries1[i].a_perm != entries2[i].a_perm)
663             {
664               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
665                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
666               return 1;
667             }
668         }
669     }
670 #endif
671   }
672
673   return 0;
674 }