File: 0000-0122.c

package info (click to toggle)
librecast 0.11.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,760 kB
  • sloc: ansic: 31,144; asm: 28,570; sh: 3,164; makefile: 713; python: 70
file content (172 lines) | stat: -rw-r--r-- 4,989 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2023 Brett Sheffield <bacs@librecast.net> */

#include "test.h"
#include "testdata.h"
#include "testnet.h"
#include "testsync.h"
#include <errno.h>
#include <librecast_pvt.h>
#include <librecast/mdex.h>
#include <librecast/mtree.h>
#include <librecast/net.h>
#include <librecast/sync.h>
#include <sys/resource.h>
#include <unistd.h>

#define LINUX_SRC "/usr/src/linux-6.5.5"
#define MAXFILESZ 1048576
#define MAXFILES 10
#define MAXDIRS 5
#define DEPTH 2
#define TIMEOUT_SECONDS 3600

/*
 * test 0122
 *
 * Sync the Linux kernel using lc_syncfile()
 *
 * Compare the resulting directories and ensure they match.
 */

static sem_t sem_recv;

struct pkg_s {
	char *src;
	char *dst;
};

/* append trailing slash to string, return allocated new string */
char *appendslash(char *str)
{
	size_t len = strlen(str);
	if (str[len - 1] == '/') return strdup(str);
	char *newstr = malloc(len + 2);
	assert(newstr);
	strcpy(newstr, str);
	newstr[len] = '/';
	newstr[len + 1] = '\0';
	return newstr;
}

void *thread_recv(void *arg)
{
	struct pkg_s *pkg = (struct pkg_s *)arg;
	const int flags =
		SYNC_RECURSE | SYNC_ATIME | SYNC_MTIME | SYNC_OWNER | SYNC_GROUP | SYNC_MODE;
	ssize_t rc;
	lc_ctx_t *lctx = lc_ctx_new();
	pthread_cleanup_push((void (*)(void *))lc_ctx_free, lctx);
	lc_ctx_stream(lctx, stderr);
	lc_ctx_debug(lctx, LCTX_DEBUG_SYNCFILE);
	char *slashed = appendslash(pkg->src);
	assert(slashed);
	pthread_cleanup_push(free, slashed);
	test_log("src (with trailing slash appended): '%s'\n", slashed);
	rc = lc_syncfile_hash(lctx, slashed, pkg->dst, NULL, NULL, NULL, flags);
	test_assert(rc > 0, "lc_syncfile_hash returned %zi", rc);
	if (rc == -1) perror("lc_syncfile_hash");
	pthread_cleanup_pop(1); /* free(slashed) */
	pthread_cleanup_pop(1); /* lc_ctx_free */
	sem_post(&sem_recv);
	return NULL;
}

int main(int argc, char *argv[])
{
	(void)argc;
	lc_ctx_t *lctx;
	mdex_t *mdex;
	lc_share_t *share;
	pthread_t tid_recv;
	struct pkg_s pkg_recv = {0};
	struct timespec timeout = {0};
	char *dst = NULL;
	char *rpath = NULL;
	int rc;

	test_cap_require(CAP_NET_ADMIN);
	test_name("lc_syncfile() - recursive file syncing");
	test_require_net(TEST_NET_BASIC);

	/* create source directory tree and files */
#if 0
	char *src = NULL;
	rc = test_createtestdirs(basename(argv[0]), &src, &dst);
	if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status;
	test_random_meta(src, TEST_OWN|TEST_MOD);
	rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, TEST_OWN|TEST_MOD);
	if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst;
#else
	char *src = LINUX_SRC;
	rc = test_createtestdir(basename(argv[0]), &dst, "dst");
	if (!test_assert(rc == 0, "test_createtestdir() - dst directory")) goto err_free_src_dst;
#endif

	/* how many open files are we permitted? */
	struct rlimit rlim;
	rc = getrlimit(RLIMIT_NOFILE, &rlim);
	test_log("RLIMIT_NOFILE cur = %i, max = %i\n", rlim.rlim_cur, rlim.rlim_max);

	/* use realpath for source */
	rpath = realpath(src, NULL);

	/* index source tree */
	mdex = mdex_init(512);
	if (!test_assert(mdex != NULL, "mdex_init()")) goto err_free_src_dst;
	mdex->stream = stderr;
	mdex->debug = MDEX_DEBUG_FILE;
	test_log("mdexing files...\n");
	rc = mdex_addfile(mdex, rpath, NULL, MDEX_RECURSE);
	test_log("mdexing done.\n");
	if (!test_assert(rc == 0, "mdex_addfile() returned %i", rc)) goto err_mdex_free;

#if 0
	/* XXX; match src and dst match */
	char cmd[128];
	//snprintf(cmd, sizeof cmd, "rsync -avq %s/ %s", src, dst);
	snprintf(cmd, sizeof cmd, "cp -Rp %s/. %s", src, dst);
	test_log("`%s`\n", cmd);
	if (system(cmd)) { test_assert(0, "cmd failed"); goto err_free_src_dst; }
#endif

	/* share the mdex */
	lctx = lc_ctx_new();
	if (!test_assert(lctx != NULL, "lc_ctx_new()")) goto err_mdex_free;
	share = lc_share(lctx, mdex, 0, NULL, NULL, LC_SHARE_LOOPBACK);
	if (!test_assert(share != NULL, "lc_share()")) goto err_free_lctx;

	/* start receive thread, sync files */
	rc = sem_init(&sem_recv, 0, 0);
	if (!test_assert(rc == 0, "sem_init(sem_recv)")) goto err_unshare;
	pkg_recv.src = mdex_sharepath(mdex, rpath);
	pkg_recv.dst = dst;
	test_log("syncing '%s' => '%s'\n", pkg_recv.src, pkg_recv.dst);
	rc = pthread_create(&tid_recv, NULL, thread_recv, &pkg_recv);
	if (!test_assert(rc == 0, "create recv thread")) goto err_sem_destroy;

	/* handle timeout */
	clock_gettime(CLOCK_REALTIME, &timeout);
	timeout.tv_sec += TIMEOUT_SECONDS;
	if ((rc = sem_timedwait(&sem_recv, &timeout)) == -1 && errno == ETIMEDOUT) {
		pthread_cancel(tid_recv);
	}
	test_assert(rc == 0, "timeout waiting for recv thread");
	pthread_join(tid_recv, NULL);

	/* verify src and dst match */
	test_verify_dirs(rpath, dst);
err_sem_destroy:
	sem_destroy(&sem_recv);
err_unshare:
	lc_unshare(share);
err_free_lctx:
	lc_ctx_free(lctx);
err_mdex_free:
	mdex_free(mdex);
err_free_src_dst:
	free(dst);
	free(pkg_recv.src);
	free(rpath);
	return test_status;
}