getfacl.c revision 75491
1/*-
2 * Copyright (c) 1999-2001 Robert N M Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$FreeBSD: head/bin/getfacl/getfacl.c 75491 2001-04-13 19:24:28Z jedgar $
27 */
28/*
29 * getfacl -- POSIX.1e utility to extract ACLs from files and directories
30 * and send the results to stdout
31 */
32
33#include <sys/types.h>
34#include <sys/param.h>
35#include <sys/acl.h>
36#include <sys/stat.h>
37#include <err.h>
38#include <errno.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <unistd.h>
42
43int	more_than_one = 0;
44
45static void
46usage(void)
47{
48
49	fprintf(stderr, "getfacl [-d] [files ...]\n");
50}
51
52/*
53 * return an ACL corresponding to the permissions
54 * contained in struct stat
55 */
56static acl_t
57acl_from_stat(struct stat sb)
58{
59	acl_t acl;
60	acl_entry_t entry;
61	acl_permset_t perms;
62
63	/* create the ACL */
64	acl = acl_init(3);
65	if (!acl)
66		return NULL;
67
68	/* First entry: ACL_USER_OBJ */
69	if (acl_create_entry(&acl, &entry) == -1)
70		return NULL;
71	if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
72		return NULL;
73
74	if (acl_get_permset(entry, &perms) == -1)
75		return NULL;
76	if (acl_clear_perms(perms) == -1)
77		return NULL;
78
79	/* calculate user mode */
80	if (sb.st_mode & S_IRUSR)
81		if (acl_add_perm(perms, ACL_READ) == -1)
82			return NULL;
83	if (sb.st_mode & S_IWUSR)
84		if (acl_add_perm(perms, ACL_WRITE) == -1)
85			return NULL;
86	if (sb.st_mode & S_IXUSR)
87		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
88			return NULL;
89	if (acl_set_permset(entry, perms) == -1)
90		return NULL;
91
92	/* Second entry: ACL_GROUP_OBJ */
93	if (acl_create_entry(&acl, &entry) == -1)
94		return NULL;
95	if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
96		return NULL;
97
98	if (acl_get_permset(entry, &perms) == -1)
99		return NULL;
100	if (acl_clear_perms(perms) == -1)
101		return NULL;
102
103	/* calculate group mode */
104	if (sb.st_mode & S_IRGRP)
105		if (acl_add_perm(perms, ACL_READ) == -1)
106			return NULL;
107	if (sb.st_mode & S_IWGRP)
108		if (acl_add_perm(perms, ACL_WRITE) == -1)
109			return NULL;
110	if (sb.st_mode & S_IXGRP)
111		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
112			return NULL;
113	if (acl_set_permset(entry, perms) == -1)
114		return NULL;
115
116	/* Third entry: ACL_OTHER */
117	if (acl_create_entry(&acl, &entry) == -1)
118		return NULL;
119	if (acl_set_tag_type(entry, ACL_OTHER) == -1)
120		return NULL;
121
122	if (acl_get_permset(entry, &perms) == -1)
123		return NULL;
124	if (acl_clear_perms(perms) == -1)
125		return NULL;
126
127	/* calculate other mode */
128	if (sb.st_mode & S_IROTH)
129		if (acl_add_perm(perms, ACL_READ) == -1)
130			return NULL;
131	if (sb.st_mode & S_IWOTH)
132		if (acl_add_perm(perms, ACL_WRITE) == -1)
133			return NULL;
134	if (sb.st_mode & S_IXOTH)
135		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
136			return NULL;
137	if (acl_set_permset(entry, perms) == -1)
138		return NULL;
139
140	return(acl);
141}
142
143static int
144print_acl(char *path, acl_type_t type)
145{
146	struct stat	sb;
147	acl_t	acl;
148	char	*acl_text;
149	int	error;
150
151	error = stat(path, &sb);
152	if (error == -1) {
153		perror(path);
154		return(-1);
155	}
156
157	if (more_than_one)
158		printf("\n");
159	else
160		more_than_one++;
161
162	printf("#file:%s\n#owner:%d\n#group:%d\n", path, sb.st_uid, sb.st_gid);
163
164	acl = acl_get_file(path, type);
165	if (!acl) {
166		if (errno != EOPNOTSUPP) {
167			warn("%s", path);
168			return(-1);
169		}
170		errno = 0;
171		if (type != ACL_TYPE_ACCESS)
172			return(0);
173		acl = acl_from_stat(sb);
174		if (!acl) {
175			perror("acl_from_stat()");
176			return(-1);
177		}
178	}
179
180	acl_text = acl_to_text(acl, 0);
181	if (!acl_text) {
182		perror(path);
183		return(-1);
184	}
185
186	printf("%s", acl_text);
187
188	acl_free(acl);
189	acl_free(acl_text);
190
191	return(0);
192}
193
194static int
195print_acl_from_stdin(acl_type_t type)
196{
197	char	pathname[PATH_MAX];
198	int	carried_error = 0;
199
200	pathname[sizeof(pathname) - 1] = '\0';
201	while (fgets(pathname, sizeof(pathname), stdin)) {
202		/* remove the \n */
203		pathname[strlen(pathname) - 1] = '\0';
204		if (print_acl(pathname, type) == -1) {
205			carried_error = -1;
206		}
207	}
208
209	return(carried_error);
210}
211
212int
213main(int argc, char *argv[])
214{
215	acl_type_t	type = ACL_TYPE_ACCESS;
216	int	carried_error = 0;
217	int	ch, error, i;
218
219	while ((ch = getopt(argc, argv, "d")) != -1)
220		switch(ch) {
221		case 'd':
222			type = ACL_TYPE_DEFAULT;
223			break;
224		default:
225			usage();
226			return(-1);
227		}
228	argc -= optind;
229	argv += optind;
230
231	if (argc == 0) {
232		error = print_acl_from_stdin(type);
233		return(error);
234	}
235
236	for (i = 0; i < argc; i++) {
237		if (!strcmp(argv[i], "-")) {
238			error = print_acl_from_stdin(type);
239			if (error == -1)
240				carried_error = -1;
241		} else {
242			error = print_acl(argv[i], type);
243			if (error == -1)
244				carried_error = -1;
245		}
246	}
247
248	return(carried_error);
249}
250