btrfs-progs/send-test.c
Rakesh Pandit 08255d5342 Btrfs-progs: remove unsed pthread attribute objects
Threads always use default attributes in all tools, so pthread
attribute objects and their initializations are of no use. Just pass
NULL as attr attribute to pthread_create for default attributes.

Signed-off-by: Rakesh Pandit <rakesh@tuxera.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
2014-04-22 14:33:35 +02:00

450 lines
9.8 KiB
C

/*
* Copyright (C) 2013 SUSE. All rights reserved.
*
* This code is adapted from cmds-send.c and cmds-receive.c,
* Both of which are:
*
* Copyright (C) 2012 Alexander Block. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <stdint.h>
#include <dirent.h>
#include <pthread.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <libgen.h>
#include <mntent.h>
#include <limits.h>
#include <stdlib.h>
#include <asm/types.h>
#include <uuid/uuid.h>
/*
* This should be compilable without the rest of the btrfs-progs
* source distribution.
*/
#if BTRFS_FLAT_INCLUDES
#include "send-utils.h"
#include "send-stream.h"
#else
#include <btrfs/send-utils.h>
#include <btrfs/send-stream.h>
#endif /* BTRFS_FLAT_INCLUDES */
static int pipefd[2];
struct btrfs_ioctl_send_args io_send = {0, };
static char *subvol_path;
static char *root_path;
struct recv_args {
char *full_subvol_path;
char *root_path;
};
void usage(int error)
{
printf("send-test <btrfs root> <subvol>\n");
if (error)
exit(error);
}
static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
void *user)
{
struct recv_args *r = user;
char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
r->full_subvol_path = path_cat(r->root_path, path);
uuid_unparse(uuid, uuid_str);
printf("subvol\t%s\t%llu\t%s\n", uuid_str,
(unsigned long long)ctransid, r->full_subvol_path);
return 0;
}
static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
const u8 *parent_uuid, u64 parent_ctransid,
void *user)
{
struct recv_args *r = user;
char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
char parent_uuid_str[BTRFS_UUID_UNPARSED_SIZE];
r->full_subvol_path = path_cat(r->root_path, path);
uuid_unparse(uuid, uuid_str);
uuid_unparse(parent_uuid, parent_uuid_str);
printf("snapshot\t%s\t%llu\t%s\t%llu\t%s\n", uuid_str,
(unsigned long long)ctransid, parent_uuid_str,
(unsigned long long)parent_ctransid, r->full_subvol_path);
return 0;
}
static int print_mkfile(const char *path, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("mkfile\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_mkdir(const char *path, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("mkdir\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_mknod(const char *path, u64 mode, u64 dev, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("mknod\t%llo\t0x%llx\t%s\n", (unsigned long long)mode,
(unsigned long long)dev, full_path);
free(full_path);
return 0;
}
static int print_mkfifo(const char *path, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("mkfifo\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_mksock(const char *path, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("mksock\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_symlink(const char *path, const char *lnk, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("symlink\t%s\t%s\n", lnk, full_path);
free(full_path);
return 0;
}
static int print_rename(const char *from, const char *to, void *user)
{
struct recv_args *r = user;
char *full_from = path_cat(r->full_subvol_path, from);
char *full_to = path_cat(r->full_subvol_path, to);
printf("rename\t%s\t%s\n", from, to);
free(full_from);
free(full_to);
return 0;
}
static int print_link(const char *path, const char *lnk, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("link\t%s\t%s\n", lnk, full_path);
free(full_path);
return 0;
}
static int print_unlink(const char *path, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("unlink\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_rmdir(const char *path, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("rmdir\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_write(const char *path, const void *data, u64 offset,
u64 len, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("write\t%llu\t%llu\t%s\n", (unsigned long long)offset,
(unsigned long long)len, full_path);
free(full_path);
return 0;
}
static int print_clone(const char *path, u64 offset, u64 len,
const u8 *clone_uuid, u64 clone_ctransid,
const char *clone_path, u64 clone_offset,
void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("clone\t%s\t%s\n", full_path, clone_path);
free(full_path);
return 0;
}
static int print_set_xattr(const char *path, const char *name,
const void *data, int len, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("set_xattr\t%s\t%s\t%d\n", full_path,
name, len);
free(full_path);
return 0;
}
static int print_remove_xattr(const char *path, const char *name, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("remove_xattr\t%s\t%s\n", full_path, name);
free(full_path);
return 0;
}
static int print_truncate(const char *path, u64 size, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("truncate\t%llu\t%s\n", (unsigned long long)size, full_path);
free(full_path);
return 0;
}
static int print_chmod(const char *path, u64 mode, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("chmod\t%llo\t%s\n", (unsigned long long)mode, full_path);
free(full_path);
return 0;
}
static int print_chown(const char *path, u64 uid, u64 gid, void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("chown\t%llu\t%llu\t%s\n", (unsigned long long)uid,
(unsigned long long)gid, full_path);
free(full_path);
return 0;
}
static int print_utimes(const char *path, struct timespec *at,
struct timespec *mt, struct timespec *ct,
void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("utimes\t%s\n", full_path);
free(full_path);
return 0;
}
static int print_update_extent(const char *path, u64 offset, u64 len,
void *user)
{
struct recv_args *r = user;
char *full_path = path_cat(r->full_subvol_path, path);
printf("update_extent\t%s\t%llu\t%llu\n", full_path, offset, len);
free(full_path);
return 0;
}
static struct btrfs_send_ops send_ops_print = {
.subvol = print_subvol,
.snapshot = print_snapshot,
.mkfile = print_mkfile,
.mkdir = print_mkdir,
.mknod = print_mknod,
.mkfifo = print_mkfifo,
.mksock = print_mksock,
.symlink = print_symlink,
.rename = print_rename,
.link = print_link,
.unlink = print_unlink,
.rmdir = print_rmdir,
.write = print_write,
.clone = print_clone,
.set_xattr = print_set_xattr,
.remove_xattr = print_remove_xattr,
.truncate = print_truncate,
.chmod = print_chmod,
.chown = print_chown,
.utimes = print_utimes,
.update_extent = print_update_extent,
};
static void *process_thread(void *arg_)
{
int ret;
while (1) {
ret = btrfs_read_and_process_send_stream(pipefd[0],
&send_ops_print, arg_, 0);
if (ret)
break;
}
if (ret > 0)
ret = 0;
return ERR_PTR(ret);
}
int main(int argc, char **argv)
{
int ret = 0;
int subvol_fd;
pthread_t t_read;
void *t_err = NULL;
struct recv_args r;
if (argc != 3)
usage(EINVAL);
root_path = realpath(argv[1], NULL);
if (!root_path) {
ret = errno;
usage(ret);
}
subvol_path = realpath(argv[2], NULL);
if (!subvol_path) {
ret = errno;
usage(ret);
}
r.full_subvol_path = subvol_path;
r.root_path = root_path;
subvol_fd = open(subvol_path, O_RDONLY|O_NOATIME);
if (subvol_fd < 0) {
ret = errno;
fprintf(stderr, "ERROR: Subvolume open failed. %s\n",
strerror(ret));
goto out;
}
ret = pipe(pipefd);
if (ret < 0) {
ret = errno;
fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(ret));
goto out;
}
ret = pthread_create(&t_read, NULL, process_thread, &r);
if (ret < 0) {
ret = errno;
fprintf(stderr, "ERROR: pthread create failed. %s\n",
strerror(ret));
goto out;
}
io_send.send_fd = pipefd[1];
io_send.clone_sources_count = 0;
io_send.clone_sources = NULL;
io_send.parent_root = 0;
io_send.flags = BTRFS_SEND_FLAG_NO_FILE_DATA;
ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
if (ret) {
ret = errno;
fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
strerror(ret));
goto out;
}
close(pipefd[1]);
ret = pthread_join(t_read, &t_err);
if (ret) {
fprintf(stderr, "ERROR: pthread_join failed: %s\n",
strerror(ret));
goto out;
}
if (t_err) {
ret = (long int)t_err;
fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
"(%s)\n", (long int)t_err, strerror(ret));
goto out;
}
out:
return !!ret;
}