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 * Copyright (c) 2019, Joyent, Inc.
27 */
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 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 nvlist_free(res);
222 if (silent == 0 && etext != NULL) {
223 if (!sattr)
224 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
225 "%s: %s: cannot move extended attributes, "),
226 cmd, infile);
227 else
228 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
229 "%s: %s: cannot move extended system "
230 "attributes, "), cmd, infile);
231 perror(etext);
232 }
233 done:
234 if (dirp)
235 (void) closedir(dirp);
236 if (sattrfd != -1)
237 (void) close(sattrfd);
238 if (tattrfd != -1)
239 (void) close(tattrfd);
240 if (asfd != -1)
241 (void) close(asfd);
242 if (atfd != -1)
243 (void) close(atfd);
244 if (indfd != -1)
245 (void) close(indfd);
246 if (outdfd != -1)
247 (void) close(outdfd);
248 nvlist_free(response);
249 if (etext != NULL)
250 return (1);
251 else
252 return (0);
253 }
254
255 /*
256 * The function returns non default extended system attribute list
257 * associated with 'fname' and returns NULL when an error has occured
258 * or when only extended system attributes other than archive,
259 * av_modified or crtime are set.
260 *
261 * The function returns system attribute list for the following cases:
262 *
263 * - any extended system attribute other than the default attributes
264 * ('archive', 'av_modified' and 'crtime') is set
265 * - nvlist has NULL name string
266 * - nvpair has data type of 'nvlist'
267 * - default data type.
268 */
269
270 nvlist_t *
sysattr_list(const char * cmd,int fd,const char * fname)271 sysattr_list(const char *cmd, int fd, const char *fname)
272 {
273 boolean_t value;
274 data_type_t type;
275 nvlist_t *response;
276 nvpair_t *pair;
277 f_attr_t fattr;
278 char *name;
279
280 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
281 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
282 "%s: %s: fgetattr failed\n"),
283 cmd, fname);
284 return (NULL);
285 }
286 pair = NULL;
287 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
288
289 name = nvpair_name(pair);
290
291 if (name != NULL)
292 fattr = name_to_attr(name);
293 else
294 return (response);
295
296 type = nvpair_type(pair);
297 switch (type) {
298 case DATA_TYPE_BOOLEAN_VALUE:
299 if (nvpair_value_boolean_value(pair,
300 &value) != 0) {
301 (void) fprintf(stderr,
302 dgettext(TEXT_DOMAIN, "%s "
303 "nvpair_value_boolean_value "
304 "failed\n"), cmd);
305 continue;
306 }
307 if (value && fattr != F_ARCHIVE &&
308 fattr != F_AV_MODIFIED)
309 return (response);
310 break;
311 case DATA_TYPE_UINT64_ARRAY:
312 if (fattr != F_CRTIME)
313 return (response);
314 break;
315 case DATA_TYPE_NVLIST:
316 default:
317 return (response);
318 }
319 }
320 nvlist_free(response);
321 return (NULL);
322 }
323