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 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 * 271 sysattr_list(char *cmd, int fd, 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 }