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