xref: /illumos-gate/usr/src/lib/libcmdutils/common/process_xattrs.c (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
27 
28 #include "libcmdutils.h"
29 
30 
31 /*
32  * Gets file descriptors of attribute directories for source and target
33  * attribute files
34  */
35 int
36 get_attrdirs(int indfd, int outdfd, char *attrfile, int *sfd, int *tfd)
37 {
38 	int	pwdfd;
39 	int	fd1;
40 	int	fd2;
41 
42 	pwdfd = open(".", O_RDONLY);
43 	if ((pwdfd != -1) && (fchdir(indfd) == 0)) {
44 		if ((fd1 = attropen(attrfile, ".", O_RDONLY)) == -1) {
45 			(void) fchdir(pwdfd);
46 			(void) close(pwdfd);
47 			return (1);
48 		}
49 		*sfd = fd1;
50 	} else {
51 		(void) fchdir(pwdfd);
52 		(void) close(pwdfd);
53 		return (1);
54 	}
55 	if (fchdir(outdfd) == 0) {
56 		if ((fd2 = attropen(attrfile, ".", O_RDONLY)) == -1) {
57 			(void) fchdir(pwdfd);
58 			(void) close(pwdfd);
59 			return (1);
60 		}
61 		*tfd = fd2;
62 	} else {
63 		(void) fchdir(pwdfd);
64 		(void) close(pwdfd);
65 		return (1);
66 	}
67 	(void) fchdir(pwdfd);
68 	return (0);
69 }
70 
71 /*
72  * mv_xattrs - Copies the content of the extended attribute files. Then
73  * 	moves the extended system attributes from the input attribute files
74  *      to the target attribute files. Moves the extended system attributes
75  *	from source to the target file. This function returns 0 on success
76  *	and nonzero on error.
77  */
78 int
79 mv_xattrs(char *cmd, char *infile, char *outfile, int sattr, int silent)
80 {
81 	int srcfd = -1;
82 	int indfd = -1;
83 	int outdfd = -1;
84 	int tmpfd = -1;
85 	int sattrfd = -1;
86 	int tattrfd = -1;
87 	int asfd = -1;
88 	int atfd = -1;
89 	DIR *dirp = NULL;
90 	struct dirent *dp = NULL;
91 	char *etext = NULL;
92 	struct stat st1;
93 	struct stat st2;
94 	nvlist_t *response = NULL;
95 	nvlist_t *res = NULL;
96 
97 	if ((srcfd = open(infile, O_RDONLY)) == -1) {
98 		etext = dgettext(TEXT_DOMAIN, "cannot open source");
99 		goto error;
100 	}
101 	if (sattr)
102 		response = sysattr_list(cmd, srcfd, infile);
103 
104 	if ((indfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) {
105 		etext = dgettext(TEXT_DOMAIN, "cannot openat source");
106 		goto error;
107 	}
108 	if ((outdfd = attropen(outfile, ".", O_RDONLY)) == -1) {
109 		etext = dgettext(TEXT_DOMAIN, "cannot attropen target");
110 		goto error;
111 	}
112 	if ((tmpfd = dup(indfd)) == -1) {
113 		etext = dgettext(TEXT_DOMAIN, "cannot dup descriptor");
114 		goto error;
115 
116 	}
117 	if ((dirp = fdopendir(tmpfd)) == NULL) {
118 		etext = dgettext(TEXT_DOMAIN, "cannot access source");
119 		goto error;
120 	}
121 	while ((dp = readdir(dirp)) != NULL) {
122 		if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
123 		    (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
124 		    dp->d_name[2] == '\0') ||
125 		    (sysattr_type(dp->d_name) == _RO_SATTR) ||
126 		    (sysattr_type(dp->d_name) == _RW_SATTR))
127 			continue;
128 
129 		if ((sattrfd = openat(indfd, dp->d_name,
130 		    O_RDONLY)) == -1) {
131 			etext = dgettext(TEXT_DOMAIN,
132 			    "cannot open src attribute file");
133 			goto error;
134 		}
135 		if (fstat(sattrfd, &st1) < 0) {
136 			etext = dgettext(TEXT_DOMAIN,
137 			    "could not stat attribute file");
138 			goto error;
139 		}
140 		if ((tattrfd = openat(outdfd, dp->d_name,
141 		    O_RDWR|O_CREAT|O_TRUNC, st1.st_mode)) == -1) {
142 			etext = dgettext(TEXT_DOMAIN,
143 			    "cannot open target attribute file");
144 			goto error;
145 		}
146 		if (fstat(tattrfd, &st2) < 0) {
147 			etext = dgettext(TEXT_DOMAIN,
148 			    "could not stat attribute file");
149 			goto error;
150 		}
151 		if (writefile(sattrfd, tattrfd, infile, outfile, dp->d_name,
152 		    dp->d_name, &st1, &st2) != 0) {
153 			etext = dgettext(TEXT_DOMAIN,
154 			    "failed to copy extended attribute "
155 			    "from source to target");
156 			goto error;
157 		}
158 
159 		errno = 0;
160 		if (sattr) {
161 			/*
162 			 * Gets non default extended system attributes from
163 			 * source to copy to target.
164 			 */
165 			if (dp->d_name != NULL)
166 				res = sysattr_list(cmd, sattrfd, dp->d_name);
167 
168 			if (res != NULL &&
169 			    get_attrdirs(indfd, outdfd, dp->d_name, &asfd,
170 			    &atfd) != 0) {
171 				etext = dgettext(TEXT_DOMAIN,
172 				    "Failed to open attribute files");
173 				goto error;
174 			}
175 			/*
176 			 * Copy extended system attribute from source
177 			 * attribute file to target attribute file
178 			 */
179 			if (res != NULL &&
180 			    (renameat(asfd, VIEW_READWRITE, atfd,
181 			    VIEW_READWRITE) != 0)) {
182 				if (errno == EPERM)
183 					etext = dgettext(TEXT_DOMAIN,
184 					    "Permission denied -"
185 					    "failed to move system attribute");
186 				else
187 					etext = dgettext(TEXT_DOMAIN,
188 					    "failed to move extended "
189 					    "system attribute");
190 				goto error;
191 			}
192 		}
193 		if (sattrfd != -1)
194 			(void) close(sattrfd);
195 		if (tattrfd != -1)
196 			(void) close(tattrfd);
197 		if (asfd != -1)
198 			(void) close(asfd);
199 		if (atfd != -1)
200 			(void) close(atfd);
201 		if (res != NULL) {
202 			nvlist_free(res);
203 			res = NULL;
204 		}
205 	}
206 	errno = 0;
207 	/* Copy extended system attribute from source to target */
208 
209 	if (response != NULL) {
210 		if (renameat(indfd, VIEW_READWRITE, outdfd,
211 		    VIEW_READWRITE) == 0)
212 			goto done;
213 
214 		if (errno == EPERM)
215 			etext = dgettext(TEXT_DOMAIN, "Permission denied");
216 		else
217 			etext = dgettext(TEXT_DOMAIN,
218 			    "failed to move system attribute");
219 	}
220 error:
221 	nvlist_free(res);
222 	if (silent == 0 && etext != NULL) {
223 		if (!sattr)
224 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
225 			    "%s: %s: cannot move extended attributes, "),
226 			    cmd, infile);
227 		else
228 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
229 			    "%s: %s: cannot move extended system "
230 			    "attributes, "), cmd, infile);
231 		perror(etext);
232 	}
233 done:
234 	if (dirp)
235 		(void) closedir(dirp);
236 	if (sattrfd != -1)
237 		(void) close(sattrfd);
238 	if (tattrfd != -1)
239 		(void) close(tattrfd);
240 	if (asfd != -1)
241 		(void) close(asfd);
242 	if (atfd != -1)
243 		(void) close(atfd);
244 	if (indfd != -1)
245 		(void) close(indfd);
246 	if (outdfd != -1)
247 		(void) close(outdfd);
248 	nvlist_free(response);
249 	if (etext != NULL)
250 		return (1);
251 	else
252 		return (0);
253 }
254 
255 /*
256  * The function returns non default extended system attribute list
257  * associated with 'fname' and returns NULL when an error has occured
258  * or when only extended system attributes other than archive,
259  * av_modified or crtime are set.
260  *
261  * The function returns system attribute list for the following cases:
262  *
263  *	- any extended system attribute other than the default attributes
264  *	  ('archive', 'av_modified' and 'crtime') is set
265  *	- nvlist has NULL name string
266  *	- nvpair has data type of 'nvlist'
267  *	- default data type.
268  */
269 
270 nvlist_t *
271 sysattr_list(char *cmd, int fd, char *fname)
272 {
273 	boolean_t	value;
274 	data_type_t	type;
275 	nvlist_t	*response;
276 	nvpair_t	*pair;
277 	f_attr_t	fattr;
278 	char		*name;
279 
280 	if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
281 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
282 		    "%s: %s: fgetattr failed\n"),
283 		    cmd, fname);
284 		return (NULL);
285 	}
286 	pair = NULL;
287 	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
288 
289 		name = nvpair_name(pair);
290 
291 		if (name != NULL)
292 			fattr = name_to_attr(name);
293 		else
294 			return (response);
295 
296 		type = nvpair_type(pair);
297 		switch (type) {
298 			case DATA_TYPE_BOOLEAN_VALUE:
299 				if (nvpair_value_boolean_value(pair,
300 				    &value) != 0) {
301 					(void) fprintf(stderr,
302 					    dgettext(TEXT_DOMAIN, "%s "
303 					    "nvpair_value_boolean_value "
304 					    "failed\n"), cmd);
305 					continue;
306 				}
307 				if (value && fattr != F_ARCHIVE &&
308 				    fattr != F_AV_MODIFIED)
309 					return (response);
310 				break;
311 			case DATA_TYPE_UINT64_ARRAY:
312 				if (fattr != F_CRTIME)
313 					return (response);
314 				break;
315 			case DATA_TYPE_NVLIST:
316 			default:
317 				return (response);
318 		}
319 	}
320 	nvlist_free(response);
321 	return (NULL);
322 }
323