*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
*
* GPL HEADER END
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2012, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
* [pfid,tfid,name] tracked from (1) is used for this.
*/
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <fcntl.h>
+#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <utime.h>
+#include <time.h>
#include <sys/xattr.h>
+#include <linux/types.h>
-#include <libcfs/libcfsutil.h>
+#include <libcfs/util/string.h>
#include <lustre/lustreapi.h>
#include "lustre_rsync.h"
+#include "callvpe.h"
#define REPLICATE_STATUS_VER 1
#define CLEAR_INTERVAL 100
#define DINFO 1
#define DTRACE 2
-/* Not used; declared for fulfilling obd.c's dependency. */
-command_t cmdlist[0];
-extern int obd_initialize(int argc, char **argv);
-
/* Information for processing a changelog record. This structure is
allocated on the heap instead of allocating large variables on the
stack. */
char spfid[LR_FID_STR_LEN];
char sname[NAME_MAX + 1];
char name[NAME_MAX + 1];
- char src[PATH_MAX + 1];
- char dest[PATH_MAX + 1];
+ char src[3 * PATH_MAX + 1];
+ char dest[3 * PATH_MAX + 1];
char path[PATH_MAX + 1];
char savedpath[PATH_MAX + 1];
char link[PATH_MAX + 1];
char linktmp[PATH_MAX + 1];
- char cmd[PATH_MAX];
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;
/* Command line options */
struct option long_opts[] = {
- {"source", required_argument, 0, 's'},
- {"target", required_argument, 0, 't'},
- {"mdt", required_argument, 0, 'm'},
- {"user", required_argument, 0, 'u'},
- {"statuslog", required_argument, 0, 'l'},
- {"verbose", no_argument, 0, 'v'},
- {"xattr", required_argument, 0, 'x'},
- {"dry-run", no_argument, 0, 'z'},
- /* Undocumented options follow */
- {"cl-clear", required_argument, 0, 'c'},
- {"use-rsync", no_argument, 0, 'r'},
- {"rsync-threshold", required_argument, 0, 'y'},
- {"start-recno", required_argument, 0, 'n'},
- {"abort-on-err",no_argument, 0, 'a'},
- {"debug", required_argument, 0, 'd'},
- {"debuglog", required_argument, 0, 'D'},
- {0, 0, 0, 0}
-};
+ { .val = 'l', .name = "statuslog", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt", .has_arg = required_argument },
+ { .val = 's', .name = "source", .has_arg = required_argument },
+ { .val = 't', .name = "target", .has_arg = required_argument },
+ { .val = 'u', .name = "user", .has_arg = required_argument },
+ { .val = 'v', .name = "verbose", .has_arg = no_argument },
+ { .val = 'x', .name = "xattr", .has_arg = required_argument },
+ { .val = 'z', .name = "dry-run", .has_arg = no_argument },
+ /* Undocumented options follow */
+ { .val = 'a', .name = "abort-on-err", .has_arg = no_argument },
+ { .val = 'c', .name = "cl-clear", .has_arg = required_argument },
+ { .val = 'd', .name = "debug", .has_arg = required_argument },
+ { .val = 'D', .name = "debuglog", .has_arg = required_argument },
+ { .val = 'n', .name = "start-recno", .has_arg = required_argument },
+ { .val = 'r', .name = "use-rsync", .has_arg = no_argument },
+ { .val = 'y', .name = "rsync-threshold",
+ .has_arg = required_argument },
+ { .name = NULL } };
/* Command line usage */
void lr_usage()
"\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, ...)
/* Use rsync to replicate file data */
int lr_rsync_data(struct lr_info *info)
{
- int rc;
- struct stat st_src, st_dest;
- char cmd[PATH_MAX];
+ struct stat st_src, st_dest;
+ int rc;
lr_debug(DTRACE, "Syncing data%s\n", info->tfid);
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;
- snprintf(cmd, PATH_MAX, "%s --inplace %s %s", rsync, info->src,
- info->dest);
- lr_debug(DTRACE, "\t%s %s\n", cmd, info->tfid);
- status = system(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);
info->bufsize = bufsize;
}
- while (1) {
- rsize = read(fd_src, info->buf, bufsize);
- if (rsize == 0) {
- break;
- } else if (rsize < 0) {
- rc = -errno;
- goto out;
- }
- errno = 0;
- if (write(fd_dest, info->buf, rsize) != rsize) {
- if (errno != 0)
- rc = -errno;
- else
- rc = -EINTR;
- }
- }
- fsync(fd_dest);
+ while (1) {
+ char *buf;
+ int wsize;
+
+ buf = info->buf;
+ rsize = read(fd_src, buf, bufsize);
+ if (rsize == 0) {
+ rc = 0;
+ break;
+ }
+ if (rsize < 0) {
+ rc = -errno;
+ break;
+ }
+ do {
+ wsize = write(fd_dest, buf, rsize);
+ if (wsize <= 0) {
+ rc = -errno;
+ break;
+ }
+ rsize -= wsize;
+ buf += wsize;
+ } while (rsize > 0);
+ }
+ fsync(fd_dest);
out:
- if (fd_src != -1)
- close(fd_src);
- if (fd_dest != -1)
- close(fd_dest);
+ if (fd_src != -1)
+ close(fd_src);
+ if (fd_dest != -1)
+ close(fd_dest);
- return rc;
+ return rc;
}
/* Copy data from source to destination */
}
/* 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;
strlen(status->ls_source)) == 0) {
/* Strip source fs path and replace with target fs path. */
link = info->linktmp + strlen(status->ls_source);
- snprintf(info->src, PATH_MAX, "%s%s",
+ snprintf(info->src, sizeof(info->src), "%s%s",
status->ls_targets[info->target_no], link);
link = info->src;
} else {
link = info->linktmp;
}
- strncpy(info->link, link, PATH_MAX);
- info->link[PATH_MAX] = '\0';
-
- return rc;
+ rc = snprintf(info->link, sizeof(info->link), "%s", link);
+ if (rc >= sizeof(info->link))
+ rc = -E2BIG;
+ return rc;
}
/* Create file/directory/device file/symlink. */
} else {
rc = mknod(info->dest, S_IFREG | 0777, 0);
}
- if (rc)
- return -errno;
+
+ if (rc < 0) {
+ if (errno == EEXIST)
+ rc = 0;
+ else
+ return -errno;
+ }
/* Sync data and attributes */
if (info->type == CL_CREATE || info->type == CL_MKDIR) {
int lr_add_pc(const char *pfid, const char *tfid, const char *name)
{
- struct lr_parent_child_list *p;
-
- p = calloc(1, sizeof(*p));
- if (!p)
- return -ENOMEM;
- strcpy(p->pc_log.pcl_pfid, pfid);
- strcpy(p->pc_log.pcl_tfid, tfid);
- strcpy(p->pc_log.pcl_name, name);
-
- p->pc_next = parents;
- parents = p;
- return 0;
+ struct lr_parent_child_list *p;
+ size_t len;
+
+ p = calloc(1, sizeof(*p));
+ if (p == NULL)
+ return -ENOMEM;
+ 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 = 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 = 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;
+
+ p->pc_next = parents;
+ parents = p;
+ return 0;
+
+out_err:
+ free(p);
+ return -E2BIG;
}
void lr_cascade_move(const char *fid, const char *dest, struct lr_info *info)
{
struct lr_parent_child_list *curr, *prev;
- char *d;
+ char d[4 * PATH_MAX + 1];
int rc;
- d = calloc(1, PATH_MAX + 1);
prev = curr = parents;
while (curr) {
if (strcmp(curr->pc_log.pcl_pfid, fid) == 0) {
- snprintf(d, PATH_MAX, "%s/%s", dest,
- curr->pc_log.pcl_name);
- snprintf(info->src, PATH_MAX, "%s/%s/%s",
- status->ls_targets[info->target_no],
- SPECIAL_DIR, curr->pc_log.pcl_tfid);
+ if (snprintf(d, sizeof(d), "%s/%s", dest,
+ curr->pc_log.pcl_name) >= sizeof(d)) {
+ fprintf(stderr, "Buffer truncated\n");
+ return;
+ }
+ if (snprintf(info->src, sizeof(info->src), "%s/%s/%s",
+ status->ls_targets[info->target_no],
+ SPECIAL_DIR, curr->pc_log.pcl_tfid) >=
+ sizeof(info->src))
+ return;
rc = rename(info->src, d);
if (rc == -1) {
fprintf(stderr, "Error renaming file "
info->src, d, errno);
errors++;
}
- lr_cascade_move(curr->pc_log.pcl_tfid, d, info);
if (curr == parents)
parents = curr->pc_next;
else
prev->pc_next = curr->pc_next;
+ lr_cascade_move(curr->pc_log.pcl_tfid, d, info);
free(curr);
prev = curr = parents;
curr = curr->pc_next;
}
}
-
- free(d);
}
/* remove [info->spfid, info->sfid] from parents */
{
int rc;
- snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
status->ls_targets[info->target_no], SPECIAL_DIR,
info->tfid);
/* Recursively remove directory and its contents */
int lr_rm_recursive(struct lr_info *info)
{
- int rc;
-
- snprintf(info->cmd, PATH_MAX, "rm -rf %s", info->dest);
- rc = system(info->cmd);
- if (rc == -1)
- rc = -errno;
+ char *args[] = {
+ "rm",
+ "-rf",
+ "--",
+ info->dest,
+ NULL,
+ };
+ extern char **environ;
+ int status;
+ int rc;
+
+ 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. */
{
int rc;
- snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
status->ls_targets[info->target_no], SPECIAL_DIR,
info->tfid);
rc = lr_rmfile(info);
/* Is f2p(pfid)+name != f2p(tfid)? If not the file has moved. */
len = strlen(info->path);
if (len == 1 && info->path[0] == '/')
- snprintf(info->dest, PATH_MAX, "%s", info->name);
+ snprintf(info->dest, sizeof(info->dest), "%s", info->name);
else if (len - 1 > 0 && info->path[len - 1] == '/')
- snprintf(info->dest, PATH_MAX, "%s%s", info->path, info->name);
+ snprintf(info->dest, sizeof(info->dest), "%s%s", info->path,
+ info->name);
else
- snprintf(info->dest, PATH_MAX, "%s/%s", info->path, info->name);
+ snprintf(info->dest, sizeof(info->dest), "%s/%s", info->path,
+ info->name);
lr_debug(DTRACE, "dest = %s; savedpath = %s\n", info->dest,
info->savedpath);
/* Is f2p(pfid) present on the target? If not, the parent has
moved */
if (!mkspecial) {
- snprintf(info->dest, PATH_MAX, "%s/%s", status->ls_targets[0],
- info->path);
+ snprintf(info->dest, sizeof(info->dest), "%s/%s",
+ status->ls_targets[0], info->path);
if (access(info->dest, F_OK) != 0) {
lr_debug(DTRACE, "create: parent %s not found\n",
info->dest);
}
for (info->target_no = 0; info->target_no < status->ls_num_targets;
info->target_no++) {
- snprintf(info->dest, PATH_MAX, "%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s",
status->ls_targets[info->target_no], info->savedpath);
lr_get_FID_PATH(status->ls_source, info->tfid, info->src,
- PATH_MAX);
+ PATH_MAX);
if (!mkspecial)
rc1 = lr_mkfile(info);
rc = rc1;
continue;
}
- snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
status->ls_targets[info->target_no], info->path,
info->name);
int special_dest = 0;
char srcpath[PATH_MAX + 1] = "";
- LASSERT(info->is_extended);
+ assert(info->is_extended);
rc_src = lr_get_path(info, info->spfid);
if (rc_src < 0 && rc_src != -ENOENT)
info->target_no++) {
if (!rc_dest) {
- snprintf(info->dest, PATH_MAX, "%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s",
status->ls_targets[info->target_no],
info->path);
if (access(info->dest, F_OK) != 0) {
rc_dest = -errno;
} else {
- snprintf(info->dest, PATH_MAX, "%s/%s/%s",
- status->ls_targets[info->target_no],
- info->path, info->name);
+ snprintf(info->dest, sizeof(info->dest),
+ "%s/%s/%s",
+ status->ls_targets[info->target_no],
+ info->path, info->name);
}
lr_debug(DINFO, "dest path %s rc_dest=%d\n", info->dest,
rc_dest);
}
if (rc_dest == -ENOENT) {
- snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
status->ls_targets[info->target_no],
SPECIAL_DIR, info->sfid);
special_dest = 1;
}
if (!rc_src) {
- snprintf(info->src, PATH_MAX, "%s/%s/%s",
+ snprintf(info->src, sizeof(info->src), "%s/%s/%s",
status->ls_targets[info->target_no],
srcpath, info->sname);
lr_debug(DINFO, "src path %s rc_src=%d\n", info->src,
}
if (rc_src == -ENOENT || (access(info->src, F_OK) != 0 &&
errno == ENOENT)) {
- snprintf(info->src, PATH_MAX, "%s/%s/%s",
+ snprintf(info->src, sizeof(info->src), "%s/%s/%s",
status->ls_targets[info->target_no],
SPECIAL_DIR, info->sfid);
special_src = 1;
lr_debug(DINFO, "rename returns %d\n", rc1);
}
- if (special_src) {
+ if (special_src)
rc1 = lr_remove_pc(info->spfid, info->sfid);
- if (!special_dest)
- lr_cascade_move(info->sfid, info->dest, info);
- }
- if (special_dest)
+
+ if (!special_dest)
+ lr_cascade_move(info->sfid, info->dest, info);
+ else
rc1 = lr_add_pc(info->pfid, info->sfid, info->name);
lr_debug(DINFO, "move: %s [to] %s rc1=%d, errno=%d\n",
int lr_link(struct lr_info *info)
{
int i;
- int len;
int rc;
int rc1;
struct stat st;
for (info->target_no = 0; info->target_no < status->ls_num_targets;
info->target_no++) {
- info->src[0] = 0;
- info->dest[0] = 0;
- rc1 = 0;
+ info->src[0] = 0;
+ info->dest[0] = 0;
+ rc1 = 0;
+
+ /*
+ * The changelog record has the new parent directory FID and
+ * name of the target file. So info->dest can be constructed
+ * by getting the path of the new parent directory and
+ * appending the target file name.
+ */
+ rc1 = lr_get_path(info, info->pfid);
+ lr_debug(rc1 ? 0 : DTRACE, "\tparent fid2path %s, %s, rc=%d\n",
+ info->path, info->name, rc1);
+
+ if (rc1 == 0) {
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
+ status->ls_targets[info->target_no],
+ info->path, info->name);
+ lr_debug(DINFO, "link destination is %s\n", info->dest);
+ }
+
+ /* Search through the hardlinks to get the src */
+ for (i = 0; i < st.st_nlink && info->src[0] == 0; i++) {
+ size_t len;
- /* Search through the hardlinks to get the src and dest */
- for (i = 0; i < st.st_nlink && (info->src[0] == 0 ||
- info->dest[0] == 0); i++) {
rc1 = lr_get_path_ln(info, info->tfid, i);
lr_debug(rc1 ? 0:DTRACE, "\tfid2path %s, %s, %d rc=%d\n",
info->path, info->name, i, rc1);
if (rc1)
break;
- len = strlen(info->path) - strlen(info->name);
- if (len > 0 && strcmp(info->path + len,
- info->name) == 0)
- snprintf(info->dest, PATH_MAX, "%s/%s",
- status->ls_targets[info->target_no],
- info->path);
- else if (info->src[0] == 0)
- snprintf(info->src, PATH_MAX, "%s/%s",
- status->ls_targets[info->target_no],
- info->path);
- }
+ /*
+ * Compare the path of target FID with info->dest
+ * to find out info->src.
+ */
+ len = sizeof(status->ls_targets[info->target_no]) +
+ sizeof(info->path);
+ char srcpath[len + 1];
+
+ snprintf(srcpath, sizeof(srcpath), "%s/%s",
+ status->ls_targets[info->target_no],
+ info->path);
+
+ if (strcmp(srcpath, info->dest) != 0) {
+ snprintf(info->src, sizeof(info->src), "%s",
+ srcpath);
+ lr_debug(DINFO, "link source is %s\n",
+ info->src);
+ }
+ }
if (rc1) {
rc = rc1;
continue;
}
- if (info->src[0] == 0 || info->dest[0] == 0)
- /* Could not find the source or destination.
- This can happen when some links don't exist
- anymore. */
- return -EINVAL;
-
if (info->src[0] == 0)
- snprintf(info->src, PATH_MAX, "%s/%s/%s",
+ snprintf(info->src, sizeof(info->src), "%s/%s/%s",
status->ls_targets[info->target_no],
SPECIAL_DIR, info->tfid);
else if (info->dest[0] == 0)
- snprintf(info->dest, PATH_MAX, "%s/%s/%s",
+ snprintf(info->dest, sizeof(info->dest), "%s/%s/%s",
status->ls_targets[info->target_no],
SPECIAL_DIR, info->tfid);
- rc1 = link(info->src, info->dest);
- lr_debug(rc1?0:DINFO, "link: %s [to] %s; rc1=%d %s\n",
- info->src, info->dest, rc1, strerror(errno));
+ rc1 = link(info->src, info->dest);
+ lr_debug(DINFO, "link: %s [to] %s; rc1=%d %s\n",
+ info->src, info->dest, rc1,
+ strerror(rc1 ? errno : 0));
if (rc1)
rc = rc1;
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, PATH_MAX, "%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, PATH_MAX, "%s/%s",
- status->ls_targets[info->target_no], info->path);
lr_debug(DINFO, "setxattr: %s %s %s\n", info->src, info->dest,
info->tfid);
/* Parse a line of changelog entry */
int lr_parse_line(void *priv, struct lr_info *info)
{
- struct changelog_ext_rec *rec;
-
- if (llapi_changelog_recv(priv, &rec) != 0)
- return -1;
-
- info->is_extended = CHANGELOG_REC_EXTENDED(rec);
- info->recno = rec->cr_index;
- info->type = rec->cr_type;
- sprintf(info->tfid, DFID, PFID(&rec->cr_tfid));
- sprintf(info->pfid, DFID, PFID(&rec->cr_pfid));
- strncpy(info->name, rec->cr_name, rec->cr_namelen);
-
- if (fid_is_sane(&rec->cr_sfid)) {
- sprintf(info->sfid, DFID, PFID(&rec->cr_sfid));
- sprintf(info->spfid, DFID, PFID(&rec->cr_spfid));
- strncpy(info->sname, changelog_rec_sname(rec),
- changelog_rec_snamelen(rec));
- info->sname[changelog_rec_snamelen(rec)] = '\0';
+ struct changelog_rec *rec;
+ struct changelog_ext_rename *rnm;
+ size_t namelen;
+ size_t copylen = sizeof(info->name);
+
+ if (llapi_changelog_recv(priv, &rec) != 0)
+ return -1;
+
+ info->is_extended = !!(rec->cr_flags & CLF_RENAME);
+ info->recno = rec->cr_index;
+ info->type = rec->cr_type;
+ snprintf(info->tfid, sizeof(info->tfid), DFID, PFID(&rec->cr_tfid));
+ snprintf(info->pfid, sizeof(info->pfid), DFID, PFID(&rec->cr_pfid));
+
+ namelen = strnlen(changelog_rec_name(rec), rec->cr_namelen);
+ if (copylen > namelen + 1)
+ copylen = namelen + 1;
+ snprintf(info->name, copylen, "%s", changelog_rec_name(rec));
+
+ /* Don't use rnm if CLF_RENAME isn't set */
+ rnm = changelog_rec_rename(rec);
+ if (rec->cr_flags & CLF_RENAME && !fid_is_zero(&rnm->cr_sfid)) {
+ copylen = sizeof(info->sname);
+
+ snprintf(info->sfid, sizeof(info->sfid), DFID,
+ PFID(&rnm->cr_sfid));
+ snprintf(info->spfid, sizeof(info->spfid), DFID,
+ PFID(&rnm->cr_spfid));
+ namelen = changelog_rec_snamelen(rec);
+ if (copylen > namelen + 1)
+ copylen = namelen + 1;
+ snprintf(info->sname, copylen, "%s", changelog_rec_sname(rec));
if (verbose > 1)
printf("Rec %lld: %d %s %s\n", info->recno, info->type,
info->name, info->sname);
} else {
- info->name[rec->cr_namelen] = '\0';
-
if (verbose > 1)
printf("Rec %lld: %d %s\n", info->recno, info->type,
info->name);
/* Initialize the replication parameters */
int lr_init_status()
{
- size_t size = sizeof(struct lustre_rsync_status) + PATH_MAX;
+ size_t size = sizeof(struct lustre_rsync_status) + PATH_MAX + 1;
if (status != NULL)
return 0;
if (logbackedup)
return;
- snprintf(backupfile, PATH_MAX, "%s.old", statuslog);
+ snprintf(backupfile, sizeof(backupfile), "%s.old", statuslog);
(void) rename(statuslog, backupfile);
logbackedup = 1;
struct lustre_rsync_status *s;
int fd = -1;
size_t size;
- size_t read_size = sizeof(struct lustre_rsync_status) + PATH_MAX;
+ size_t read_size = sizeof(struct lustre_rsync_status) + PATH_MAX + 1;
int rc = 0;
if (statuslog == NULL)
return 0;
s = calloc(1, read_size);
- if (s == NULL)
- GOTO(out, rc = -ENOMEM);
-
- fd = open(statuslog, O_RDONLY);
- if (fd == -1)
- GOTO(out, rc = -errno);
- size = read(fd, s, read_size);
- if (size != read_size)
- GOTO(out, rc = -EINVAL);
- if (read_size < s->ls_size) {
- read_size = s->ls_size;
- s = lr_grow_buf(s, read_size);
- if (s == NULL)
- GOTO(out, rc = -ENOMEM);
- if (lseek(fd, 0, SEEK_SET) == -1)
- GOTO(out, rc = -errno);
- size = read(fd, s, read_size);
- if (size != read_size)
- GOTO(out, rc = -EINVAL);
- }
+ if (s == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ fd = open(statuslog, O_RDONLY);
+ if (fd == -1) {
+ rc = -errno;
+ goto out;
+ }
+
+ size = read(fd, s, read_size);
+ if (size != read_size) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (read_size < s->ls_size) {
+ read_size = s->ls_size;
+ s = lr_grow_buf(s, read_size);
+ if (s == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ size = read(fd, s, read_size);
+ if (size != read_size) {
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
+ while (read(fd, &rec, sizeof(rec)) != 0) {
+ tmp = calloc(1, sizeof(*tmp));
+ if (!tmp) {
+ rc = -ENOMEM;
+ goto out;
+ }
- while (read(fd, &rec, sizeof(rec)) != 0) {
- tmp = calloc(1, sizeof(*tmp));
- if (!tmp)
- GOTO(out, rc = -ENOMEM);
tmp->pc_log = rec;
tmp->pc_next = parents;
parents = tmp;
if (status->ls_num_targets == 0) {
if (status->ls_size != s->ls_size) {
status = lr_grow_buf(status, s->ls_size);
- if (status == NULL)
- GOTO(out, rc = -ENOMEM);
+ if (status == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
status->ls_size = s->ls_size;
}
status->ls_num_targets = s->ls_num_targets;
memcpy(status->ls_targets, s->ls_targets,
- PATH_MAX * s->ls_num_targets);
+ (PATH_MAX + 1) * s->ls_num_targets);
}
if (status->ls_last_recno == -1)
status->ls_last_recno = s->ls_last_recno;
- if (status->ls_registration[0] == '\0')
- strncpy(status->ls_registration, s->ls_registration,
- LR_NAME_MAXLEN);
+ if (status->ls_registration[0] == '\0')
+ snprintf(status->ls_registration,
+ sizeof(status->ls_registration), "%s",
+ s->ls_registration);
- if (status->ls_mdt_device[0] == '\0')
- strncpy(status->ls_mdt_device, s->ls_mdt_device,
- LR_NAME_MAXLEN);
+ if (status->ls_mdt_device[0] == '\0')
+ snprintf(status->ls_mdt_device,
+ sizeof(status->ls_mdt_device), "%s",
+ s->ls_mdt_device);
- if (status->ls_source_fs[0] == '\0')
- strncpy(status->ls_source_fs, s->ls_source_fs,
- LR_NAME_MAXLEN);
+ if (status->ls_source_fs[0] == '\0')
+ snprintf(status->ls_source_fs,
+ sizeof(status->ls_source_fs), "%s",
+ s->ls_source_fs);
- if (status->ls_source[0] == '\0')
- strncpy(status->ls_source, s->ls_source, PATH_MAX);
+ if (status->ls_source[0] == '\0')
+ snprintf(status->ls_source,
+ sizeof(status->ls_source), "%s",
+ s->ls_source);
out:
if (fd != -1)
processing. */
int lr_clear_cl(struct lr_info *info, int force)
{
- char mdt_device[LR_NAME_MAXLEN + 1];
- long long rec;
- int rc = 0;
+ char mdt_device[LR_NAME_MAXLEN + 1];
+ 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.
- */
- strncpy(mdt_device, status->ls_mdt_device,
- LR_NAME_MAXLEN);
+ */
+ 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
int len;
/* Locate rsync */
- snprintf(rsync, PATH_MAX, "%s -p %s", TYPE, RSYNC);
+ snprintf(rsync, sizeof(rsync), "%s -p %s", TYPE, RSYNC);
fp = popen(rsync, "r");
if (fp == NULL)
return -1;
- if (fgets(rsync, PATH_MAX, fp) == NULL) {
+ if (fgets(rsync, sizeof(rsync), fp) == NULL) {
fclose(fp);
return -1;
}
fclose(fp);
/* Determine the version of rsync */
- snprintf(rsync_ver, PATH_MAX, "%s --version", rsync);
+ snprintf(rsync_ver, sizeof(rsync_ver), "%s --version", rsync);
fp = popen(rsync_ver, "r");
if (fp == NULL)
return -1;
- if (fgets(rsync_ver, PATH_MAX, fp) == NULL) {
+ if (fgets(rsync_ver, sizeof(rsync_ver), fp) == NULL) {
fclose(fp);
return -1;
}
if (statuslog != NULL)
printf("Statuslog: %s\n", statuslog);
printf("Changelog registration: %s\n", status->ls_registration);
- printf("Starting changelog record: "LPD64"\n", status->ls_last_recno);
+ printf("Starting changelog record: %jd\n",
+ (uintmax_t)status->ls_last_recno);
if (noxattr)
printf("Replicate xattrs: no\n");
if (noclear)
"mountpoint.\n");
goto out;
}
- if (status->ls_mdt_device[0] == '\0')
- snprintf(status->ls_mdt_device, LR_NAME_MAXLEN, "%s%s",
- status->ls_source_fs, DEFAULT_MDT);
+
+ if (status->ls_mdt_device[0] == '\0') {
+ int len;
+
+ len = snprintf(status->ls_mdt_device,
+ sizeof(status->ls_mdt_device), "%s%s",
+ status->ls_source_fs, DEFAULT_MDT);
+ if (len >= sizeof(status->ls_mdt_device)) {
+ rc = -E2BIG;
+ goto out;
+ }
+ }
ext = calloc(1, sizeof(struct lr_info));
if (ext == NULL) {
}
for (i = 0, xattr_not_supp = 0; i < status->ls_num_targets; i++) {
- snprintf(info->dest, PATH_MAX, "%s/%s", status->ls_targets[i],
- SPECIAL_DIR);
+ snprintf(info->dest, sizeof(info->dest), "%s/%s",
+ status->ls_targets[i], SPECIAL_DIR);
rc = mkdir(info->dest, 0777);
if (rc == -1 && errno != EEXIST) {
fprintf(stderr, "Error writing to target path %s.\n",
lr_print_status(info);
- /* Open changelogs for consumption*/
- rc = llapi_changelog_start(&changelog_priv, CHANGELOG_FLAG_BLOCK,
- status->ls_source_fs, status->ls_last_recno);
+ /* Open changelogs for consumption*/
+ rc = llapi_changelog_start(&changelog_priv,
+ CHANGELOG_FLAG_BLOCK |
+ CHANGELOG_FLAG_JOBID |
+ CHANGELOG_FLAG_EXTRA_FLAGS,
+ status->ls_mdt_device, status->ls_last_recno);
if (rc < 0) {
fprintf(stderr, "Error opening changelog file for fs %s.\n",
status->ls_source_fs);
goto out;
}
+ rc = llapi_changelog_set_xflags(changelog_priv,
+ 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);
+ goto out;
+ }
+
while (!quit && lr_parse_line(changelog_priv, info) == 0) {
rc = 0;
if (info->type == CL_RENAME && !info->is_extended) {
memcpy(info->spfid, info->pfid, sizeof(info->spfid));
memcpy(info->tfid, ext->tfid, sizeof(info->tfid));
memcpy(info->pfid, ext->pfid, sizeof(info->pfid));
- strncpy(info->sname, info->name, sizeof(info->sname));
- strncpy(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_IOCTL:
- case CL_MARK:
- /* Nothing needs to be done for these entries */
- default:
- break;
- }
- DEBUG_EXIT(info, rc);
+ 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 */
+ /* fallthrough */
+ default:
+ break;
+ }
+
+ 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 */
- strncpy(status->ls_source, optarg, PATH_MAX);
+ snprintf(status->ls_source, sizeof(status->ls_source),
+ "%s", optarg);
break;
case 't':
status->ls_num_targets++;
status->ls_num_targets = numtargets;
}
newsize = sizeof (struct lustre_rsync_status) +
- (status->ls_num_targets * PATH_MAX);
+ (status->ls_num_targets * (PATH_MAX + 1));
if (status->ls_size != newsize) {
status->ls_size = newsize;
status = lr_grow_buf(status, newsize);
if (status == NULL)
return -ENOMEM;
}
- strncpy(status->ls_targets[status->ls_num_targets - 1],
- optarg,
- PATH_MAX);
- break;
- case 'm':
- strncpy(status->ls_mdt_device, optarg, LR_NAME_MAXLEN);
- break;
- case 'u':
- strncpy(status->ls_registration, optarg,
- LR_NAME_MAXLEN);
+ snprintf(status->ls_targets[status->ls_num_targets - 1],
+ sizeof(status->ls_targets[0]), "%s", optarg);
+ break;
+ case 'm':
+ snprintf(status->ls_mdt_device,
+ sizeof(status->ls_mdt_device),
+ "%s", optarg);
+ break;
+ case 'u':
+ snprintf(status->ls_registration,
+ sizeof(status->ls_registration),
+ "%s", optarg);
break;
case 'l':
statuslog = optarg;
break;
case 'D':
/* Undocumented option debug log file */
+ if (debug_log != NULL)
+ fclose(debug_log);
debug_log = fopen(optarg, "a");
if (debug_log == NULL) {
printf("Cannot open %s for debug log\n",
return -1;
}
- /* This plumbing is needed for some of the ioctls behind
- llapi calls to work. */
- if (obd_initialize(argc, argv) < 0) {
- fprintf(stderr, "obd_initialize failed.\n");
- exit(-1);
- }
-
rc = lr_locate_rsync();
if (use_rsync && rc != 0) {
fprintf(stderr, "Error: unable to locate %s.\n", RSYNC);