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
get_attrdirs(int indfd,int outdfd,char * attrfile,int * sfd,int * tfd)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
mv_xattrs(char * cmd,char * infile,char * outfile,int sattr,int silent)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 *
sysattr_list(char * cmd,int fd,char * fname)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