ninenano

Client implementation of the 9P protocol for constrained devices

git clone https://git.8pit.net/ninenano.git

  1#include <fcntl.h>
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include <errno.h>
  5
  6#include <sys/stat.h>
  7#include <sys/types.h>
  8
  9#include "9p.h"
 10#include "vfs.h"
 11#include "9pfs.h"
 12#include "xtimer.h"
 13
 14#include "lwip.h"
 15#include "lwip/netif.h"
 16
 17#include "net/af.h"
 18#include "net/ipv6/addr.h"
 19#include "net/sock/tcp.h"
 20
 21#include "embUnit.h"
 22#include "../../util.h"
 23
 24/**
 25 * 9P file system superblock.
 26 */
 27static _9pfs fs;
 28
 29/**
 30 * Mount point where the 9pfs is mounted.
 31 */
 32static vfs_mount_t mountp;
 33
 34static void
 35set_up(void)
 36{
 37	int ret;
 38
 39	mountp.mount_point = "/mnt";
 40	mountp.fs = &_9p_file_system;
 41	mountp.private_data = &fs;
 42
 43	_9pinit(&fs.ctx, recvfn, sendfn);
 44	if ((ret = vfs_mount(&mountp)))
 45		fprintf(stderr, "vfs_mount failed: %d\n", ret);
 46}
 47
 48static void
 49tear_down(void)
 50{
 51	int ret;
 52
 53	if ((ret = vfs_umount(&mountp)))
 54		fprintf(stderr, "vfs_umount failed: %d\n", ret);
 55}
 56
 57static void
 58test_9pfs__create_and_remove_directory(void)
 59{
 60	struct stat st;
 61
 62	TEST_ASSERT_EQUAL_INT(0, vfs_mkdir("/mnt/foo/wtf", S_IRUSR|S_IWUSR));
 63	TEST_ASSERT_EQUAL_INT(0, vfs_rmdir("/mnt/foo/wtf"));
 64
 65	TEST_ASSERT(vfs_stat("/mnt/foo/wtf", &st) != 0);
 66	TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
 67}
 68
 69static void
 70test_9pfs__read(void)
 71{
 72	int fd;
 73	ssize_t n;
 74	char dest[BUFSIZ];
 75
 76	fd = vfs_open("/mnt/foo/bar/hello", OREAD, S_IRUSR|S_IWUSR);
 77	TEST_ASSERT(fd >= 0);
 78
 79	n = vfs_read(fd, dest, BUFSIZ - 1);
 80	TEST_ASSERT_EQUAL_INT(13, n);
 81
 82	dest[n] = '\0';
 83	TEST_ASSERT_EQUAL_STRING("Hello World!\n", (char*)dest);
 84
 85	TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
 86}
 87
 88static void
 89test_9pfs__lseek_and_read(void)
 90{
 91	int fd;
 92	ssize_t n;
 93	char dest[BUFSIZ];
 94
 95	fd = vfs_open("/mnt/foo/bar/hello", OREAD, S_IRUSR|S_IWUSR);
 96	TEST_ASSERT(fd >= 0);
 97
 98	TEST_ASSERT_EQUAL_INT(6, vfs_lseek(fd, 6, SEEK_SET));
 99
100	n = vfs_read(fd, dest, BUFSIZ - 1);
101	TEST_ASSERT_EQUAL_INT(7, n);
102
103	dest[n] = '\0';
104	TEST_ASSERT_EQUAL_STRING("World!\n", (char*)dest);
105
106	TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
107}
108
109static void
110test_9pfs__create_and_delete(void)
111{
112	int fd;
113	struct stat buf;
114
115	fd = vfs_open("/mnt/foo/falafel", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
116	TEST_ASSERT(fd >= 0);
117
118	TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
119	TEST_ASSERT_EQUAL_INT(0, vfs_unlink("/mnt/foo/falafel"));
120
121	TEST_ASSERT(vfs_stat("/mnt/foo/falafel", &buf) < 0);
122}
123
124static void
125test_9pfs__write_lseek_and_read(void)
126{
127	int fd;
128	ssize_t n;
129	char *str = "foobar";
130	char dest[7];
131
132	fd = vfs_open("/mnt/writeme", O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
133	TEST_ASSERT(fd >= 0);
134
135	TEST_ASSERT_EQUAL_INT(2, cntfids(fs.ctx.fids));
136
137	n = vfs_write(fd, str, 6);
138	TEST_ASSERT_EQUAL_INT(6, n);
139
140	TEST_ASSERT_EQUAL_INT(0, vfs_lseek(fd, 0, SEEK_SET));
141
142	n = vfs_read(fd, dest, 6);
143	TEST_ASSERT_EQUAL_INT(6, n);
144
145	dest[6] = '\0';
146	TEST_ASSERT_EQUAL_STRING(str, (char*)dest);
147
148	TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
149	TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
150}
151
152static void
153test_9pfs__opendir_and_closedir(void)
154{
155	vfs_DIR dirp;
156
157	TEST_ASSERT_EQUAL_INT(0, vfs_opendir(&dirp, "/mnt/foo"));
158	TEST_ASSERT_EQUAL_INT(2, cntfids(fs.ctx.fids));
159	TEST_ASSERT_EQUAL_INT(0, vfs_closedir(&dirp));
160
161	TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
162}
163
164static void
165test_9pfs__opendir_file(void)
166{
167	vfs_DIR dirp;
168
169	TEST_ASSERT_EQUAL_INT(-ENOTDIR,
170		vfs_opendir(&dirp, "/mnt/foo/bar/hello"));
171	TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
172}
173
174static void
175test_9pfs__readdir_single_entry(void)
176{
177	vfs_DIR dirp;
178	vfs_dirent_t entry;
179
180	TEST_ASSERT_EQUAL_INT(0, vfs_opendir(&dirp, "/mnt/foo"));
181	TEST_ASSERT_EQUAL_INT(1, vfs_readdir(&dirp, &entry));
182	TEST_ASSERT_EQUAL_STRING("bar", (char*)entry.d_name);
183	TEST_ASSERT_EQUAL_INT(0, vfs_readdir(&dirp, &entry));
184
185	TEST_ASSERT_EQUAL_INT(0, vfs_closedir(&dirp));
186	TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
187}
188
189static void
190test_9pfs__readdir_multiple_entries(void)
191{
192	int i;
193	vfs_DIR dirp;
194	vfs_dirent_t entry;
195	char dirname[VFS_NAME_MAX + 1];
196
197	TEST_ASSERT_EQUAL_INT(0, vfs_opendir(&dirp, "/mnt/dirs"));
198	for (i = 1; i <= 5; i++) {
199		TEST_ASSERT_EQUAL_INT(1, vfs_readdir(&dirp, &entry));
200		snprintf(dirname, sizeof(dirname), "%d", i);
201		TEST_ASSERT_EQUAL_STRING((char*)dirname, (char*)entry.d_name);
202	}
203	TEST_ASSERT_EQUAL_INT(0, vfs_readdir(&dirp, &entry));
204
205	TEST_ASSERT_EQUAL_INT(0, vfs_closedir(&dirp));
206	TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
207}
208
209Test*
210tests_9pfs_tests(void)
211{
212	EMB_UNIT_TESTFIXTURES(fixtures) {
213		new_TestFixture(test_9pfs__read),
214		new_TestFixture(test_9pfs__lseek_and_read),
215		new_TestFixture(test_9pfs__create_and_delete),
216		new_TestFixture(test_9pfs__write_lseek_and_read),
217		new_TestFixture(test_9pfs__create_and_remove_directory),
218		new_TestFixture(test_9pfs__opendir_and_closedir),
219		new_TestFixture(test_9pfs__opendir_file),
220		new_TestFixture(test_9pfs__readdir_single_entry),
221		new_TestFixture(test_9pfs__readdir_multiple_entries),
222	};
223
224	EMB_UNIT_TESTCALLER(_9pfs_tests, set_up, tear_down, fixtures);
225	return (Test*)&_9pfs_tests;
226}
227
228int
229main(void)
230{
231	char *addr, *port;
232	sock_tcp_ep_t remote = SOCK_IPV6_EP_ANY;
233
234	GETENV(addr, "NINERIOT_ADDR");
235	GETENV(port, "NINERIOT_PPORT");
236
237	remote.port = atoi(port);
238	if (!ipv6_addr_from_str((ipv6_addr_t *)&remote.addr, addr)) {
239		fprintf(stderr, "Address '%s' is malformed\n", addr);
240		return EXIT_FAILURE;
241	}
242
243	puts("Waiting for address autoconfiguration...");
244	xtimer_sleep(3);
245
246	if (sock_tcp_connect(&psock, &remote, 0, SOCK_FLAGS_REUSE_EP) < 0) {
247		fprintf(stderr, "Couldn't connect to server\n");
248		return EXIT_FAILURE;
249	}
250
251	fs.uname = "glenda";
252	fs.aname = NULL;
253
254	TESTS_START();
255	TESTS_RUN(tests_9pfs_tests());
256	TESTS_END();
257
258	sock_tcp_disconnect(&psock);
259	return EXIT_SUCCESS;
260}