Home | History | Annotate | Download | only in common
      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  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     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 			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 (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
    284 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
    285 		    "%s: %s: fgetattr failed\n"),
    286 		    cmd, fname);
    287 		return (NULL);
    288 	}
    289 	pair = NULL;
    290 	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
    291 
    292 		name = nvpair_name(pair);
    293 
    294 		if (name != NULL)
    295 			fattr = name_to_attr(name);
    296 		else
    297 			return (response);
    298 
    299 		type = nvpair_type(pair);
    300 		switch (type) {
    301 			case DATA_TYPE_BOOLEAN_VALUE:
    302 				if (nvpair_value_boolean_value(pair,
    303 				    &value) != 0) {
    304 					(void) fprintf(stderr,
    305 					    dgettext(TEXT_DOMAIN, "%s "
    306 					    "nvpair_value_boolean_value "
    307 					    "failed\n"), cmd);
    308 					continue;
    309 				}
    310 				if (value && fattr != F_ARCHIVE &&
    311 				    fattr != F_AV_MODIFIED)
    312 					return (response);
    313 				break;
    314 			case DATA_TYPE_UINT64_ARRAY:
    315 				if (fattr != F_CRTIME)
    316 					return (response);
    317 				break;
    318 			case DATA_TYPE_NVLIST:
    319 			default:
    320 				return (response);
    321 				break;
    322 		}
    323 	}
    324 	if (response != NULL)
    325 		nvlist_free(response);
    326 	return (NULL);
    327 }
    328