acl: Complete the 2010-08-10 fix.
[pspp] / 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
32 #include "progname.h"
33 #include "read-file.h"
34 #include "xalloc.h"
35 #include "macros.h"
36
37 int
38 main (int argc, char *argv[])
39 {
40   const char *file1;
41   const char *file2;
42
43   set_program_name (argv[0]);
44
45   ASSERT (argc == 3);
46
47   file1 = argv[1];
48   file2 = argv[2];
49
50   /* Compare the contents of the two files.  */
51   {
52     size_t size1;
53     char *contents1;
54     size_t size2;
55     char *contents2;
56
57     contents1 = read_file (file1, &size1);
58     if (contents1 == NULL)
59       {
60         fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
61         fflush (stderr);
62         abort ();
63       }
64     contents2 = read_file (file2, &size2);
65     if (contents2 == NULL)
66       {
67         fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
68         fflush (stderr);
69         abort ();
70       }
71
72     if (size2 != size1)
73       {
74         fprintf (stderr, "files %s and %s have different sizes\n",
75                  file1, file2);
76         fflush (stderr);
77         abort ();
78       }
79     if (memcmp (contents1, contents2, size1) != 0)
80       {
81         fprintf (stderr, "files %s and %s have different contents\n",
82                  file1, file2);
83         fflush (stderr);
84         abort ();
85       }
86   }
87
88   /* Compare the access permissions of the two files, including ACLs.  */
89   {
90     struct stat statbuf1;
91     struct stat statbuf2;
92
93     if (stat (file1, &statbuf1) < 0)
94       {
95         fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
96         fflush (stderr);
97         abort ();
98       }
99     if (stat (file2, &statbuf2) < 0)
100       {
101         fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
102         fflush (stderr);
103         abort ();
104       }
105     if (statbuf1.st_mode != statbuf2.st_mode)
106       {
107         fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
108                  file1, file2,
109                 (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
110         return 1;
111       }
112   }
113   {
114 #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
115     static const int types[] =
116       {
117         ACL_TYPE_ACCESS
118 # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
119         , ACL_TYPE_EXTENDED
120 # endif
121       };
122     int t;
123
124     for (t = 0; t < sizeof (types) / sizeof (types[0]); t++)
125       {
126         int type = types[t];
127         acl_t acl1;
128         char *text1;
129         int errno1;
130         acl_t acl2;
131         char *text2;
132         int errno2;
133
134         acl1 = acl_get_file (file1, type);
135         if (acl1 == (acl_t)NULL)
136           {
137             text1 = NULL;
138             errno1 = errno;
139           }
140         else
141           {
142             text1 = acl_to_text (acl1, NULL);
143             if (text1 == NULL)
144               errno1 = errno;
145             else
146               errno1 = 0;
147           }
148         acl2 = acl_get_file (file2, type);
149         if (acl2 == (acl_t)NULL)
150           {
151             text2 = NULL;
152             errno2 = errno;
153           }
154         else
155           {
156             text2 = acl_to_text (acl2, NULL);
157             if (text2 == NULL)
158               errno2 = errno;
159             else
160               errno2 = 0;
161           }
162
163         if (acl1 != (acl_t)NULL)
164           {
165             if (acl2 != (acl_t)NULL)
166               {
167                 if (text1 != NULL)
168                   {
169                     if (text2 != NULL)
170                       {
171                         if (strcmp (text1, text2) != 0)
172                           {
173                             fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
174                                      file1, file2, text1, text2);
175                             return 1;
176                           }
177                       }
178                     else
179                       {
180                         fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
181                                  file1, file2);
182                         return 1;
183                       }
184                   }
185                 else
186                   {
187                     if (text2 != NULL)
188                       {
189                         fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
190                                  file1, file2);
191                         return 1;
192                       }
193                     else
194                       {
195                         if (errno1 != errno2)
196                           {
197                             fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
198                                      file1, file2, errno1, errno2);
199                             return 1;
200                           }
201                       }
202                   }
203               }
204             else
205               {
206                 fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
207                          file1, file2);
208                 return 1;
209               }
210           }
211         else
212           {
213             if (acl2 != (acl_t)NULL)
214               {
215                 fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
216                          file1, file2);
217                 return 1;
218               }
219           }
220       }
221 #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
222   int count1;
223   int count2;
224
225   count1 = acl (file1, GETACLCNT, 0, NULL);
226   count2 = acl (file2, GETACLCNT, 0, NULL);
227
228   if (count1 < 0)
229     {
230       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
231       fflush (stderr);
232       abort ();
233     }
234   if (count2 < 0)
235     {
236       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
237       fflush (stderr);
238       abort ();
239     }
240   if (count1 != count2)
241     {
242       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
243                file1, file2, count1, count2);
244       return 1;
245     }
246   else
247     {
248       aclent_t *entries1 = XNMALLOC (count1, aclent_t);
249       aclent_t *entries2 = XNMALLOC (count2, aclent_t);
250       int i;
251
252       if (acl (file1, GETACL, count1, entries1) < count1)
253         {
254           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
255           fflush (stderr);
256           abort ();
257         }
258       if (acl (file2, GETACL, count2, entries2) < count1)
259         {
260           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
261           fflush (stderr);
262           abort ();
263         }
264       for (i = 0; i < count1; i++)
265         {
266           if (entries1[i].a_type != entries2[i].a_type)
267             {
268               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
269                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
270               return 1;
271             }
272           if (entries1[i].a_id != entries2[i].a_id)
273             {
274               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
275                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
276               return 1;
277             }
278           if (entries1[i].a_perm != entries2[i].a_perm)
279             {
280               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
281                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
282               return 1;
283             }
284         }
285     }
286 # ifdef ACE_GETACL
287   count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
288   if (count1 < 0 && errno == EINVAL)
289     count1 = 0;
290   count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
291   if (count2 < 0 && errno == EINVAL)
292     count2 = 0;
293   if (count1 < 0)
294     {
295       fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
296       fflush (stderr);
297       abort ();
298     }
299   if (count2 < 0)
300     {
301       fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
302       fflush (stderr);
303       abort ();
304     }
305   if (count1 != count2)
306     {
307       fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
308                file1, file2, count1, count2);
309       return 1;
310     }
311   else if (count1 > 0)
312     {
313       ace_t *entries1 = XNMALLOC (count1, ace_t);
314       ace_t *entries2 = XNMALLOC (count2, ace_t);
315       int i;
316
317       if (acl (file1, ACE_GETACL, count1, entries1) < count1)
318         {
319           fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
320           fflush (stderr);
321           abort ();
322         }
323       if (acl (file2, ACE_GETACL, count2, entries2) < count1)
324         {
325           fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
326           fflush (stderr);
327           abort ();
328         }
329       for (i = 0; i < count1; i++)
330         {
331           if (entries1[i].a_type != entries2[i].a_type)
332             {
333               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
334                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
335               return 1;
336             }
337           if (entries1[i].a_who != entries2[i].a_who)
338             {
339               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
340                        file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who);
341               return 1;
342             }
343           if (entries1[i].a_access_mask != entries2[i].a_access_mask)
344             {
345               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
346                        file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask);
347               return 1;
348             }
349           if (entries1[i].a_flags != entries2[i].a_flags)
350             {
351               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
352                        file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags);
353               return 1;
354             }
355         }
356     }
357 # endif
358 #elif HAVE_GETACL /* HP-UX */
359   int count1;
360   int count2;
361
362   count1 = getacl (file1, 0, NULL);
363   if (count1 < 0
364       && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
365     count1 = 0;
366   count2 = getacl (file2, 0, NULL);
367   if (count2 < 0
368       && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
369     count2 = 0;
370
371   if (count1 < 0)
372     {
373       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
374       fflush (stderr);
375       abort ();
376     }
377   if (count2 < 0)
378     {
379       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
380       fflush (stderr);
381       abort ();
382     }
383   if (count1 != count2)
384     {
385       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
386                file1, file2, count1, count2);
387       return 1;
388     }
389   else if (count1 > 0)
390     {
391       struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
392       struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
393       int i;
394
395       if (getacl (file1, count1, entries1) < count1)
396         {
397           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
398           fflush (stderr);
399           abort ();
400         }
401       if (getacl (file2, count2, entries2) < count1)
402         {
403           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
404           fflush (stderr);
405           abort ();
406         }
407       for (i = 0; i < count1; i++)
408         {
409           if (entries1[i].uid != entries2[i].uid)
410             {
411               fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
412                        file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid);
413               return 1;
414             }
415           if (entries1[i].gid != entries2[i].gid)
416             {
417               fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
418                        file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid);
419               return 1;
420             }
421           if (entries1[i].mode != entries2[i].mode)
422             {
423               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
424                        file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode);
425               return 1;
426             }
427         }
428     }
429 #elif HAVE_ACLX_GET /* AIX */
430   acl_type_t type1;
431   char acl1[1000];
432   size_t aclsize1 = sizeof (acl1);
433   mode_t mode1;
434   char text1[1000];
435   size_t textsize1 = sizeof (text1);
436   acl_type_t type2;
437   char acl2[1000];
438   size_t aclsize2 = sizeof (acl2);
439   mode_t mode2;
440   char text2[1000];
441   size_t textsize2 = sizeof (text2);
442
443   /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
444      true, in AIX 5.3.  */
445   type1.u64 = ACL_ANY;
446   if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
447     {
448       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
449       fflush (stderr);
450       abort ();
451     }
452   if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0)
453     {
454       fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
455       fflush (stderr);
456       abort ();
457     }
458
459   /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
460      true, in AIX 5.3.  */
461   type2.u64 = ACL_ANY;
462   if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
463     {
464       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
465       fflush (stderr);
466       abort ();
467     }
468   if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0)
469     {
470       fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
471       fflush (stderr);
472       abort ();
473     }
474
475   if (strcmp (text1, text2) != 0)
476     {
477       fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
478                file1, file2, text1, text2);
479       return 1;
480     }
481 #elif HAVE_STATACL /* older AIX */
482   union { struct acl a; char room[4096]; } acl1;
483   union { struct acl a; char room[4096]; } acl2;
484   unsigned int i;
485
486   if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
487     {
488       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
489       fflush (stderr);
490       abort ();
491     }
492   if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
493     {
494       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
495       fflush (stderr);
496       abort ();
497     }
498
499   if (acl1.a.acl_len != acl2.a.acl_len)
500     {
501       fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
502                file1, file2, acl1.a.acl_len, acl2.a.acl_len);
503       return 1;
504     }
505   if (acl1.a.acl_mode != acl2.a.acl_mode)
506     {
507       fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
508                file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
509       return 1;
510     }
511   if (acl1.a.u_access != acl2.a.u_access
512       || acl1.a.g_access != acl2.a.g_access
513       || acl1.a.o_access != acl2.a.o_access)
514     {
515       fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
516                file1, file2,
517                acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
518                acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
519       return 1;
520     }
521   if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
522     {
523       fprintf (stderr, "files %s and %s have different ACL entries\n",
524                file1, file2);
525       return 1;
526     }
527 #elif HAVE_ACLSORT /* NonStop Kernel */
528   int count1;
529   int count2;
530
531   count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
532   count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);
533
534   if (count1 < 0)
535     {
536       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
537       fflush (stderr);
538       abort ();
539     }
540   if (count2 < 0)
541     {
542       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
543       fflush (stderr);
544       abort ();
545     }
546   if (count1 != count2)
547     {
548       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
549                file1, file2, count1, count2);
550       return 1;
551     }
552   else if (count1 > 0)
553     {
554       struct acl *entries1 = XNMALLOC (count1, struct acl);
555       struct acl *entries2 = XNMALLOC (count2, struct acl);
556       int i;
557
558       if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
559         {
560           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
561           fflush (stderr);
562           abort ();
563         }
564       if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
565         {
566           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
567           fflush (stderr);
568           abort ();
569         }
570       for (i = 0; i < count1; i++)
571         {
572           if (entries1[i].a_type != entries2[i].a_type)
573             {
574               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
575                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
576               return 1;
577             }
578           if (entries1[i].a_id != entries2[i].a_id)
579             {
580               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
581                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
582               return 1;
583             }
584           if (entries1[i].a_perm != entries2[i].a_perm)
585             {
586               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
587                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
588               return 1;
589             }
590         }
591     }
592 #endif
593   }
594
595   return 0;
596 }