#include <time.h>
#include <sys/xattr.h>
#include <linux/types.h>
-#include <linux/lustre/lustre_ioctl.h>
-#include <libcfs/util/ioctl.h>
#include <libcfs/util/string.h>
-#include <libcfs/util/parser.h>
-#include <linux/lnet/libcfs_debug.h>
#include <lustre/lustreapi.h>
#include "lustre_rsync.h"
+#include "callvpe.h"
#define REPLICATE_STATUS_VER 1
#define CLEAR_INTERVAL 100
char savedpath[PATH_MAX + 1];
char link[PATH_MAX + 1];
char linktmp[PATH_MAX + 1];
- char cmd[PATH_MAX * 10];
int bufsize;
char *buf;
receipt of a signal */
int abort_on_err = 0;
-char rsync[PATH_MAX];
-char rsync_ver[PATH_MAX];
+char rsync[PATH_MAX + 128];
+char rsync_ver[PATH_MAX * 2];
struct lr_parent_child_list *parents;
FILE *debug_log;
"\t--dry-run don't write anything\n");
}
-#define DEBUG_ENTRY(info) \
- lr_debug(D_TRACE, "***** Start %lld %s (%d) %s %s %s *****\n", \
- (info)->recno, changelog_type2str((info)->type), \
- (info)->type, (info)->tfid, (info)->pfid, (info)->name);
-
-#define DEBUG_EXIT(info, rc) \
- lr_debug(D_TRACE, "##### End %lld %s (%d) %s %s %s rc=%d #####\n", \
- (info)->recno, changelog_type2str((info)->type), \
- (info)->type, (info)->tfid, (info)->pfid, (info)->name, rc);
-
/* Print debug information. This is controlled by the value of the
global variable 'debug' */
void lr_debug(int level, const char *fmt, ...)
if (st_src.st_mtime != st_dest.st_mtime ||
st_src.st_size != st_dest.st_size) {
- /* XXX spawning off an rsync for every data sync and
- * waiting synchronously is bad for performance.
- * librsync could possibly used here. But it does not
- * seem to be of production grade. Multi-threaded
- * replication is also to be considered.
- */
- int status;
-
- if (snprintf(info->cmd, sizeof(info->cmd), "%s --inplace %s %s",
- rsync, info->src, info->dest) >= sizeof(info->cmd)) {
- rc = -E2BIG;
- goto err;
- }
- lr_debug(DTRACE, "\t%s %s\n", info->cmd, info->tfid);
- status = system(info->cmd);
- if (status == -1) {
+ /* XXX spawning off an rsync for every data sync and
+ * waiting synchronously is bad for performance.
+ * librsync could possibly used here. But it does not
+ * seem to be of production grade. Multi-threaded
+ * replication is also to be considered.
+ */
+ char *args[] = {
+ rsync,
+ "--inplace",
+ "--",
+ info->src,
+ info->dest,
+ NULL,
+ };
+ extern char **environ;
+ int status;
+
+ lr_debug(DTRACE, "\t%s %s %s %s %s %s\n", args[0], args[1],
+ args[2], args[3], args[4], info->tfid);
+
+ status = callvpe(rsync, args, environ);
+ if (status < 0) {
rc = -errno;
} else if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
lr_debug(DTRACE, "Not syncing %s and %s %s\n", info->src,
info->dest, info->tfid);
}
-err:
+
return rc;
}
}
/* Copy all attributes from file src to file dest */
-int lr_copy_attr(char *src, char *dest)
+int lr_copy_attr(const char *src, const char *dest)
{
struct stat st;
struct utimbuf time;
rc, errno);
if (rc == -1) {
if (errno != ENOTSUP) {
- fprintf(stderr, "Error replicating "
- " xattr for %s: %d\n",
- info->dest, errno);
+ fprintf(stderr,
+ "cannot replicate xattrs from '%s' to '%s': %s\n",
+ info->src, info->dest,
+ strerror(errno));
errors++;
}
rc = 0;
} else {
link = info->linktmp;
}
- strlcpy(info->link, link, sizeof(info->link));
-
+ rc = snprintf(info->link, sizeof(info->link), "%s", link);
+ if (rc >= sizeof(info->link))
+ rc = -E2BIG;
return rc;
}
p = calloc(1, sizeof(*p));
if (p == NULL)
return -ENOMEM;
- len = strlcpy(p->pc_log.pcl_pfid, pfid, sizeof(p->pc_log.pcl_pfid));
+ len = snprintf(p->pc_log.pcl_pfid, sizeof(p->pc_log.pcl_pfid),
+ "%s", pfid);
if (len >= sizeof(p->pc_log.pcl_pfid))
goto out_err;
- len = strlcpy(p->pc_log.pcl_tfid, tfid, sizeof(p->pc_log.pcl_tfid));
+ len = snprintf(p->pc_log.pcl_tfid, sizeof(p->pc_log.pcl_tfid),
+ "%s", tfid);
if (len >= sizeof(p->pc_log.pcl_tfid))
goto out_err;
- len = strlcpy(p->pc_log.pcl_name, name, sizeof(p->pc_log.pcl_name));
+ len = snprintf(p->pc_log.pcl_name, sizeof(p->pc_log.pcl_name),
+ "%s", name);
if (len >= sizeof(p->pc_log.pcl_name))
goto out_err;
/* Recursively remove directory and its contents */
int lr_rm_recursive(struct lr_info *info)
{
+ char *args[] = {
+ "rm",
+ "-rf",
+ "--",
+ info->dest,
+ NULL,
+ };
+ extern char **environ;
+ int status;
int rc;
- snprintf(info->cmd, sizeof(info->cmd), "rm -rf %s",
- info->dest);
- rc = system(info->cmd);
- if (rc == -1)
- rc = -errno;
+ status = callvpe("/bin/rm", args, environ);
+ if (status < 0)
+ rc = -errno;
+ else if (WIFEXITED(status))
+ rc = WEXITSTATUS(status) == 0 ? 0 : -EINVAL;
+ else
+ rc = -EINTR;
- return rc;
+ return rc;
}
/* Remove a file under SPECIAL_DIR with its tfid as its name. */
info->path);
if (strcmp(srcpath, info->dest) != 0) {
- strlcpy(info->src, srcpath, sizeof(info->src));
+ snprintf(info->src, sizeof(info->src), "%s",
+ srcpath);
lr_debug(DINFO, "link source is %s\n",
info->src);
}
return rc;
}
+int lr_set_dest_for_attr(struct lr_info *info)
+{
+ int rc;
+
+ snprintf(info->dest, sizeof(info->dest), "%s/%s",
+ status->ls_targets[info->target_no], info->path);
+ rc = access(info->dest, F_OK);
+ if (rc < 0)
+ rc = -errno;
+
+ if (rc != -ENOENT)
+ return rc;
+
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
+ status->ls_targets[info->target_no], SPECIAL_DIR,
+ info->tfid);
+
+ rc = access(info->dest, F_OK);
+ if (rc < 0)
+ return -errno;
+
+ return 0;
+}
+
/* Replicate file attributes */
int lr_setattr(struct lr_info *info)
{
for (info->target_no = 0; info->target_no < status->ls_num_targets;
info->target_no++) {
+ rc = lr_set_dest_for_attr(info);
+ if (rc < 0)
+ continue;
- snprintf(info->dest, sizeof(info->dest), "%s/%s",
- status->ls_targets[info->target_no], info->path);
lr_debug(DINFO, "setattr: %s %s %s", info->src, info->dest,
info->tfid);
for (info->target_no = 0; info->target_no < status->ls_num_targets;
info->target_no++) {
+ rc = lr_set_dest_for_attr(info);
+ if (rc < 0)
+ continue;
- snprintf(info->dest, sizeof(info->dest), "%s/%s",
- status->ls_targets[info->target_no], info->path);
lr_debug(DINFO, "setxattr: %s %s %s\n", info->src, info->dest,
info->tfid);
namelen = strnlen(changelog_rec_name(rec), rec->cr_namelen);
if (copylen > namelen + 1)
copylen = namelen + 1;
- strlcpy(info->name, changelog_rec_name(rec), copylen);
+ snprintf(info->name, copylen, "%s", changelog_rec_name(rec));
/* Don't use rnm if CLF_RENAME isn't set */
rnm = changelog_rec_rename(rec);
namelen = changelog_rec_snamelen(rec);
if (copylen > namelen + 1)
copylen = namelen + 1;
- strlcpy(info->sname, changelog_rec_sname(rec), copylen);
+ snprintf(info->sname, copylen, "%s", changelog_rec_sname(rec));
if (verbose > 1)
printf("Rec %lld: %d %s %s\n", info->recno, info->type,
status->ls_last_recno = s->ls_last_recno;
if (status->ls_registration[0] == '\0')
- strlcpy(status->ls_registration, s->ls_registration,
- sizeof(status->ls_registration));
+ snprintf(status->ls_registration,
+ sizeof(status->ls_registration), "%s",
+ s->ls_registration);
if (status->ls_mdt_device[0] == '\0')
- strlcpy(status->ls_mdt_device, s->ls_mdt_device,
- sizeof(status->ls_mdt_device));
+ snprintf(status->ls_mdt_device,
+ sizeof(status->ls_mdt_device), "%s",
+ s->ls_mdt_device);
if (status->ls_source_fs[0] == '\0')
- strlcpy(status->ls_source_fs, s->ls_source_fs,
- sizeof(status->ls_source_fs));
+ snprintf(status->ls_source_fs,
+ sizeof(status->ls_source_fs), "%s",
+ s->ls_source_fs);
if (status->ls_source[0] == '\0')
- strlcpy(status->ls_source, s->ls_source,
- sizeof(status->ls_source));
+ snprintf(status->ls_source,
+ sizeof(status->ls_source), "%s",
+ s->ls_source);
out:
if (fd != -1)
int lr_clear_cl(struct lr_info *info, int force)
{
char mdt_device[LR_NAME_MAXLEN + 1];
- long long rec;
int rc = 0;
if (force || info->recno > status->ls_last_recno + CLEAR_INTERVAL) {
- if (info->type == CL_RENAME)
- rec = info->recno + 1;
- else
- rec = info->recno;
if (!noclear && !dryrun) {
/* llapi_changelog_clear modifies the mdt
* device name so make a copy of it until this
* is fixed.
- */
- strlcpy(mdt_device, status->ls_mdt_device,
- sizeof(mdt_device));
+ */
+ snprintf(mdt_device, sizeof(mdt_device), "%s",
+ status->ls_mdt_device);
rc = llapi_changelog_clear(mdt_device,
status->ls_registration,
- rec);
+ info->recno);
if (rc)
- printf("Changelog clear (%s, %s, %lld) "
- "returned %d\n", status->ls_mdt_device,
- status->ls_registration, rec, rc);
- }
- if (!rc && !dryrun) {
- status->ls_last_recno = rec;
- lr_write_log();
+ printf("Changelog clear (%s, %s, %lld) "
+ "returned %d\n", status->ls_mdt_device,
+ status->ls_registration, info->recno,
+ rc);
+ }
- }
- }
+ if (!rc && !dryrun) {
+ status->ls_last_recno = info->recno;
+ lr_write_log();
+ }
+ }
- return rc;
+ return rc;
}
/* Locate a usable version of rsync. At this point we'll use any
}
rc = llapi_changelog_set_xflags(changelog_priv,
- CHANGELOG_EXTRA_FLAG_UIDGID);
+ CHANGELOG_EXTRA_FLAG_UIDGID |
+ CHANGELOG_EXTRA_FLAG_NID |
+ CHANGELOG_EXTRA_FLAG_OMODE |
+ CHANGELOG_EXTRA_FLAG_XATTR);
if (rc < 0) {
fprintf(stderr, "Error setting xflag in changelog for fs %s.\n",
status->ls_source_fs);
memcpy(info->spfid, info->pfid, sizeof(info->spfid));
memcpy(info->tfid, ext->tfid, sizeof(info->tfid));
memcpy(info->pfid, ext->pfid, sizeof(info->pfid));
- strlcpy(info->sname, info->name, sizeof(info->sname));
- strlcpy(info->name, ext->name, sizeof(info->name));
+ snprintf(info->sname, sizeof(info->sname), "%s",
+ info->name);
+ snprintf(info->name, sizeof(info->name), "%s",
+ ext->name);
info->is_extended = 1;
+ info->recno = ext->recno; /* For lr_clear_cl(). */
}
if (dryrun)
continue;
- DEBUG_ENTRY(info);
+ lr_debug(DTRACE, "***** Start %lld %s (%d) %s %s %s *****\n",
+ info->recno, changelog_type2str(info->type),
+ info->type, info->tfid, info->pfid, info->name);
switch(info->type) {
case CL_CREATE:
case CL_SETATTR:
rc = lr_setattr(info);
break;
- case CL_XATTR:
+ case CL_SETXATTR:
rc = lr_setxattr(info);
break;
case CL_CLOSE:
case CL_EXT:
case CL_OPEN:
+ case CL_GETXATTR:
+ case CL_DN_OPEN:
case CL_LAYOUT:
case CL_MARK:
/* Nothing needs to be done for these entries */
default:
break;
}
- DEBUG_EXIT(info, rc);
+
+ lr_debug(DTRACE, "##### End %lld %s (%d) %s %s %s rc=%d #####\n",
+ info->recno, changelog_type2str(info->type),
+ info->type, info->tfid, info->pfid, info->name, rc);
+
if (rc && rc != -ENOENT) {
lr_print_failure(info, rc);
errors++;
break;
}
lr_clear_cl(info, 0);
- if (debug) {
- bzero(info, sizeof(struct lr_info));
- bzero(ext, sizeof(struct lr_info));
- }
}
llapi_changelog_fini(&changelog_priv);
break;
case 's':
/* Assume absolute paths */
- strlcpy(status->ls_source, optarg,
- sizeof(status->ls_source));
+ snprintf(status->ls_source, sizeof(status->ls_source),
+ "%s", optarg);
break;
case 't':
status->ls_num_targets++;
if (status == NULL)
return -ENOMEM;
}
- strlcpy(status->ls_targets[status->ls_num_targets - 1],
- optarg, sizeof(status->ls_targets[0]));
+ snprintf(status->ls_targets[status->ls_num_targets - 1],
+ sizeof(status->ls_targets[0]), "%s", optarg);
break;
case 'm':
- strlcpy(status->ls_mdt_device, optarg,
- sizeof(status->ls_mdt_device));
+ snprintf(status->ls_mdt_device,
+ sizeof(status->ls_mdt_device),
+ "%s", optarg);
break;
case 'u':
- strlcpy(status->ls_registration, optarg,
- sizeof(status->ls_registration));
+ snprintf(status->ls_registration,
+ sizeof(status->ls_registration),
+ "%s", optarg);
break;
case 'l':
statuslog = optarg;
return -1;
}
- /* This plumbing is needed for some of the ioctls behind
- llapi calls to work. */
- register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH);
-
rc = lr_locate_rsync();
if (use_rsync && rc != 0) {
fprintf(stderr, "Error: unable to locate %s.\n", RSYNC);