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