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