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