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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <c_synonyms.h> 29 #include "libcmdutils.h" 30 31 32 /* 33 * Gets file descriptors of attribute directories for source and target 34 * attribute files 35 */ 36 int 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 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 * 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 (nvlist_alloc(&response, NV_UNIQUE_NAME, 0) != 0) { 284 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 285 "%s: %s: nvlist_alloc failed\n"), 286 cmd, fname); 287 return (NULL); 288 } 289 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) { 290 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 291 "%s: %s: fgetattr failed\n"), 292 cmd, fname); 293 nvlist_free(response); 294 return (NULL); 295 } 296 pair = NULL; 297 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 298 299 name = nvpair_name(pair); 300 301 if (name != NULL) 302 fattr = name_to_attr(name); 303 else 304 return (response); 305 306 type = nvpair_type(pair); 307 switch (type) { 308 case DATA_TYPE_BOOLEAN_VALUE: 309 if (nvpair_value_boolean_value(pair, 310 &value) != 0) { 311 (void) fprintf(stderr, 312 dgettext(TEXT_DOMAIN, "%s " 313 "nvpair_value_boolean_value " 314 "failed\n"), cmd); 315 continue; 316 } 317 if (value && fattr != F_ARCHIVE && 318 fattr != F_AV_MODIFIED) 319 return (response); 320 break; 321 case DATA_TYPE_UINT64_ARRAY: 322 if (fattr != F_CRTIME) 323 return (response); 324 break; 325 case DATA_TYPE_NVLIST: 326 default: 327 return (response); 328 break; 329 } 330 } 331 if (response != NULL) 332 nvlist_free(response); 333 return (NULL); 334 } 335