update changelog
[platform/upstream/acl.git] / chacl / chacl.c
1 /*
2  * Copyright (c) 2001-2002 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it would be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write the Free Software Foundation,
17  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <libgen.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <dirent.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/acl.h>
31 #include <acl/libacl.h>
32 #include <locale.h>
33 #include "config.h"
34
35 static int acl_delete_file (const char * path, acl_type_t type);
36 static int list_acl(char *file);
37 static int set_acl(acl_t acl, acl_t dacl, const char *fname);
38 static int walk_dir(acl_t acl, acl_t dacl, const char *fname);
39
40 static char *program;
41 static int rflag;
42
43 static void
44 usage(void)
45 {
46         fprintf(stderr, _("Usage:\n"));
47         fprintf(stderr, _("\t%s acl pathname...\n"), program);
48         fprintf(stderr, _("\t%s -b acl dacl pathname...\n"), program);
49         fprintf(stderr, _("\t%s -d dacl pathname...\n"), program);
50         fprintf(stderr, _("\t%s -R pathname...\n"), program);
51         fprintf(stderr, _("\t%s -D pathname...\n"), program);
52         fprintf(stderr, _("\t%s -B pathname...\n"), program);
53         fprintf(stderr, _("\t%s -l pathname...\t[not IRIX compatible]\n"),
54                         program);
55         fprintf(stderr, _("\t%s -r pathname...\t[not IRIX compatible]\n"),
56                         program);
57         exit(1);
58 }
59
60 int
61 main(int argc, char *argv[])
62 {
63         char *file;
64         int switch_flag = 0;            /* ensure only one switch is used */
65         int args_required = 2;  
66         int failed = 0;                 /* exit status */
67         int c;                          /* For use by getopt(3) */
68         int dflag = 0;                  /* a Default ACL is desired */
69         int bflag = 0;                  /* a both ACLs are desired */
70         int Rflag = 0;                  /* set to true to remove an acl */
71         int Dflag = 0;                  /* set to true to remove default acls */
72         int Bflag = 0;                  /* set to true to remove both acls */
73         int lflag = 0;                  /* set to true to list acls */
74         acl_t acl = NULL;               /* File ACL */
75         acl_t dacl = NULL;              /* Directory Default ACL */
76
77         program = basename(argv[0]);
78
79         setlocale(LC_CTYPE, "");
80         setlocale(LC_MESSAGES, "");
81         bindtextdomain(PACKAGE, LOCALEDIR);
82         textdomain(PACKAGE);
83
84         /* parse arguments */
85         while ((c = getopt(argc, argv, "bdlRDBr")) != -1) {
86                 if (switch_flag) 
87                         usage();
88                 switch_flag = 1;
89
90                 switch (c) {
91                         case 'b':
92                                 bflag = 1;
93                                 args_required = 3;
94                                 break;
95                         case 'd':
96                                 dflag = 1;
97                                 args_required = 2;
98                                 break;
99                         case 'R':
100                                 Rflag = 1;
101                                 args_required = 1;
102                                 break;
103                         case 'D':
104                                 Dflag = 1;
105                                 args_required = 1;
106                                 break;
107                         case 'B':
108                                 Bflag = 1;
109                                 args_required = 1;
110                                 break;
111                         case 'l':
112                                 lflag = 1;
113                                 args_required = 1;
114                                 break;
115                         case 'r':
116                                 rflag = 1;
117                                 args_required = 1;
118                                 break;
119                         default:
120                                 usage();
121                                 break;
122                 }
123         }
124
125         /* if not enough arguments quit */
126         if ((argc - optind) < args_required)
127                 usage();
128
129         /* list the acls */
130         if (lflag) {
131                 for (; optind < argc; optind++) {       
132                         file = argv[optind];
133                         if (!list_acl(file))
134                                 failed++;
135                 }
136                 return(failed);
137         }
138
139         /* remove the acls */
140         if (Rflag || Dflag || Bflag) {
141                 for (; optind < argc; optind++) {       
142                         file = argv[optind];
143                         if (!Dflag &&
144                             (acl_delete_file(file, ACL_TYPE_ACCESS) == -1)) {
145                                 fprintf(stderr, _(
146                         "%s: error removing access acl on \"%s\": %s\n"),
147                                         program, file, strerror(errno));
148                                 failed++;
149                         }
150                         if (!Rflag &&
151                             (acl_delete_file(file, ACL_TYPE_DEFAULT) == -1)) {
152                                 fprintf(stderr, _(
153                         "%s: error removing default acl on \"%s\": %s\n"),
154                                         program, file, strerror(errno));
155                                 failed++;
156                         }
157                 }
158                 return(failed);
159         }
160
161         /* file access acl */
162         if (! dflag) { 
163                 acl = acl_from_text(argv[optind]);
164                 failed = acl_check(acl, &c);
165                 if (failed < 0) {
166                         fprintf(stderr, "%s: %s - %s\n",
167                                 program, argv[optind], strerror(errno));
168                         return 1;
169                 }
170                 else if (failed > 0) {
171                         fprintf(stderr, _(
172                                 "%s: access ACL '%s': %s at entry %d\n"),
173                                 program, argv[optind], acl_error(failed), c);
174                         return 1;
175                 }
176                 optind++;
177         }
178
179
180         /* directory default acl */
181         if (bflag || dflag) {
182                 dacl = acl_from_text(argv[optind]);
183                 failed = acl_check(dacl, &c);
184                 if (failed < 0) {
185                         fprintf(stderr, "%s: %s - %s\n",
186                                 program, argv[optind], strerror(errno));
187                         return 1;
188                 }
189                 else if (failed > 0) {
190                         fprintf(stderr, _(
191                                 "%s: access ACL '%s': %s at entry %d\n"),
192                                 program, argv[optind], acl_error(failed), c);
193                         return 1;
194                 }
195                 optind++;
196         }
197
198         /* place acls on files */
199         for (; optind < argc; optind++)
200                 failed += set_acl(acl, dacl, argv[optind]);
201
202         if (acl)
203                 acl_free(acl);
204         if (dacl)
205                 acl_free(dacl);
206
207         return(failed);
208 }
209
210 /* 
211  *   deletes an access acl or directory default acl if one exists
212  */ 
213 static int 
214 acl_delete_file(const char *path, acl_type_t type)
215 {
216         int error = 0;
217
218         /* converts access ACL to a minimal ACL */
219         if (type == ACL_TYPE_ACCESS) {
220                 acl_t acl;
221                 acl_entry_t entry;
222                 acl_tag_t tag;
223
224                 acl = acl_get_file(path, ACL_TYPE_ACCESS);
225                 if (!acl)
226                         return -1;
227                 error = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
228                 while (error == 1) {
229                         acl_get_tag_type(entry, &tag);
230                         switch(tag) {
231                                 case ACL_USER:
232                                 case ACL_GROUP:
233                                 case ACL_MASK:
234                                         acl_delete_entry(acl, entry);
235                                         break;
236                          }
237                         error = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
238                 }
239                 if (!error)
240                         error = acl_set_file(path, ACL_TYPE_ACCESS, acl);
241         } else
242                 error = acl_delete_def_file(path);
243         return(error);
244 }
245
246 /*
247  *    lists the acl for a file/dir in short text form
248  *    return 0 on failure
249  *    return 1 on success
250  */
251 static int
252 list_acl(char *file)
253 {
254         acl_t acl = NULL;
255         acl_t dacl = NULL;
256         char *acl_text, *dacl_text = NULL;
257
258         if ((acl = acl_get_file(file, ACL_TYPE_ACCESS)) == NULL) {
259                 fprintf(stderr, _("%s: cannot get access ACL on '%s': %s\n"),
260                         program, file, strerror(errno));
261                 return 0;
262         }
263         if ((dacl = acl_get_file(file, ACL_TYPE_DEFAULT)) == NULL &&
264             (errno != EACCES)) {        /* EACCES given if not a directory */
265                 fprintf(stderr, _("%s: cannot get default ACL on '%s': %s\n"),
266                         program, file, strerror(errno));
267                 return 0;
268         }
269         acl_text = acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE);
270         if (acl_text == NULL) {
271                 fprintf(stderr, _("%s: cannot get access ACL text on "
272                         "'%s': %s\n"), program, file, strerror(errno));
273                 return 0;
274         }
275         if (acl_entries(dacl) > 0) {
276                 dacl_text = acl_to_any_text(dacl, NULL, ',', TEXT_ABBREVIATE);
277                 if (dacl_text == NULL) {
278                         fprintf(stderr, _("%s: cannot get default ACL text on "
279                                 "'%s': %s\n"), program, file, strerror(errno));
280                         return 0;
281                 }
282         }
283         if (dacl_text) {
284                 printf("%s [%s/%s]\n", file, acl_text, dacl_text);
285                 acl_free(dacl_text);
286         } else
287                 printf("%s [%s]\n", file, acl_text);
288         acl_free(acl_text);
289         acl_free(acl);
290         acl_free(dacl);
291         return 1;
292 }
293
294 static int
295 set_acl(acl_t acl, acl_t dacl, const char *fname)
296 {
297         int failed = 0;
298
299         if (rflag)
300                 failed += walk_dir(acl, dacl, fname);
301
302         /* set regular acl */
303         if (acl && acl_set_file(fname, ACL_TYPE_ACCESS, acl) == -1) {
304                 fprintf(stderr, _("%s: cannot set access acl on \"%s\": %s\n"),
305                         program, fname, strerror(errno));
306                 failed++;
307         }
308         /* set default acl */
309         if (dacl && acl_set_file(fname, ACL_TYPE_DEFAULT, dacl) == -1) {
310                 fprintf(stderr, _("%s: cannot set default acl on \"%s\": %s\n"),
311                         program, fname, strerror(errno));
312                 failed++;
313         }
314
315         return(failed);
316 }
317
318 static int
319 walk_dir(acl_t acl, acl_t dacl, const char *fname)
320 {
321         int failed = 0;
322         DIR *dir;
323         struct dirent64 *d;
324         char *name;
325
326         if ((dir = opendir(fname)) == NULL) {
327                 if (errno != ENOTDIR) {
328                         fprintf(stderr, _("%s: opendir failed: %s\n"),
329                                 program, strerror(errno));
330                         return(1);
331                 }
332                 return(0);      /* got a file, not an error */
333         }
334
335         while ((d = readdir64(dir)) != NULL) {
336                 /* skip "." and ".." entries */
337                 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
338                         continue;
339                 
340                 name = malloc(strlen(fname) + strlen(d->d_name) + 2);
341                 if (name == NULL) {
342                         fprintf(stderr, _("%s: malloc failed: %s\n"),
343                                 program, strerror(errno));
344                         exit(1);
345                 }
346                 sprintf(name, "%s/%s", fname, d->d_name);
347
348                 failed += set_acl(acl, dacl, name);
349                 free(name);
350         }
351         closedir(dir);
352
353         return(failed);
354 }