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