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 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 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 * 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