xref: /illumos-gate/usr/src/lib/libcmdutils/common/process_xattrs.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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 	if (res != NULL)
222 		nvlist_free(res);
223 	if (silent == 0 && etext != NULL) {
224 		if (!sattr)
225 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
226 			    "%s: %s: cannot move extended attributes, "),
227 			    cmd, infile);
228 		else
229 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
230 			    "%s: %s: cannot move extended system "
231 			    "attributes, "), cmd, infile);
232 		perror(etext);
233 	}
234 done:
235 	if (dirp)
236 		(void) closedir(dirp);
237 	if (sattrfd != -1)
238 		(void) close(sattrfd);
239 	if (tattrfd != -1)
240 		(void) close(tattrfd);
241 	if (asfd != -1)
242 		(void) close(asfd);
243 	if (atfd != -1)
244 		(void) close(atfd);
245 	if (indfd != -1)
246 		(void) close(indfd);
247 	if (outdfd != -1)
248 		(void) close(outdfd);
249 	if (response != NULL)
250 		nvlist_free(response);
251 	if (etext != NULL)
252 		return (1);
253 	else
254 		return (0);
255 }
256 
257 /*
258  * The function returns non default extended system attribute list
259  * associated with 'fname' and returns NULL when an error has occured
260  * or when only extended system attributes other than archive,
261  * av_modified or crtime are set.
262  *
263  * The function returns system attribute list for the following cases:
264  *
265  *	- any extended system attribute other than the default attributes
266  *	  ('archive', 'av_modified' and 'crtime') is set
267  *	- nvlist has NULL name string
268  *	- nvpair has data type of 'nvlist'
269  *	- default data type.
270  */
271 
272 nvlist_t *
273 sysattr_list(char *cmd, int fd, char *fname)
274 {
275 	boolean_t	value;
276 	data_type_t	type;
277 	nvlist_t	*response;
278 	nvpair_t	*pair;
279 	f_attr_t	fattr;
280 	char		*name;
281 
282 	if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
283 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
284 		    "%s: %s: fgetattr failed\n"),
285 		    cmd, fname);
286 		return (NULL);
287 	}
288 	pair = NULL;
289 	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
290 
291 		name = nvpair_name(pair);
292 
293 		if (name != NULL)
294 			fattr = name_to_attr(name);
295 		else
296 			return (response);
297 
298 		type = nvpair_type(pair);
299 		switch (type) {
300 			case DATA_TYPE_BOOLEAN_VALUE:
301 				if (nvpair_value_boolean_value(pair,
302 				    &value) != 0) {
303 					(void) fprintf(stderr,
304 					    dgettext(TEXT_DOMAIN, "%s "
305 					    "nvpair_value_boolean_value "
306 					    "failed\n"), cmd);
307 					continue;
308 				}
309 				if (value && fattr != F_ARCHIVE &&
310 				    fattr != F_AV_MODIFIED)
311 					return (response);
312 				break;
313 			case DATA_TYPE_UINT64_ARRAY:
314 				if (fattr != F_CRTIME)
315 					return (response);
316 				break;
317 			case DATA_TYPE_NVLIST:
318 			default:
319 				return (response);
320 		}
321 	}
322 	if (response != NULL)
323 		nvlist_free(response);
324 	return (NULL);
325 }
326