2019-04-29 01:40:35 +00:00
|
|
|
/*-
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
|
|
|
* Copyright (c) 2019 The FreeBSD Foundation
|
|
|
|
*
|
|
|
|
* This software was developed by BFF Storage Systems, LLC under sponsorship
|
|
|
|
* from the FreeBSD Foundation.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
2019-08-13 15:49:40 +00:00
|
|
|
*
|
|
|
|
* $FreeBSD$
|
2019-04-29 01:40:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <sys/types.h>
|
2019-04-29 16:24:51 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2019-04-29 01:40:35 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "mockfs.hh"
|
|
|
|
#include "utils.hh"
|
|
|
|
|
|
|
|
using namespace testing;
|
|
|
|
|
|
|
|
const char FULLPATH[] = "mountpoint/some_fifo";
|
|
|
|
const char RELPATH[] = "some_fifo";
|
|
|
|
const char MESSAGE[] = "Hello, World!\n";
|
|
|
|
const int msgsize = sizeof(MESSAGE);
|
|
|
|
|
|
|
|
class Fifo: public FuseTest {
|
2019-04-29 16:24:51 +00:00
|
|
|
public:
|
|
|
|
pthread_t m_child;
|
|
|
|
|
|
|
|
Fifo(): m_child(NULL) {};
|
|
|
|
|
|
|
|
void TearDown() {
|
|
|
|
if (m_child != NULL) {
|
|
|
|
pthread_join(m_child, NULL);
|
|
|
|
}
|
|
|
|
FuseTest::TearDown();
|
|
|
|
}
|
2019-04-29 01:40:35 +00:00
|
|
|
};
|
|
|
|
|
2019-04-29 16:24:51 +00:00
|
|
|
class Socket: public Fifo {};
|
|
|
|
|
2019-04-29 01:40:35 +00:00
|
|
|
/* Writer thread */
|
|
|
|
static void* writer(void* arg) {
|
|
|
|
ssize_t sent = 0;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = *(int*)arg;
|
|
|
|
while (sent < msgsize) {
|
|
|
|
ssize_t r;
|
|
|
|
|
|
|
|
r = write(fd, MESSAGE + sent, msgsize - sent);
|
|
|
|
if (r < 0)
|
|
|
|
return (void*)(intptr_t)errno;
|
|
|
|
else
|
|
|
|
sent += r;
|
|
|
|
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reading and writing FIFOs works. None of the I/O actually goes through FUSE
|
|
|
|
*/
|
|
|
|
TEST_F(Fifo, read_write)
|
|
|
|
{
|
|
|
|
mode_t mode = S_IFIFO | 0755;
|
|
|
|
const int bufsize = 80;
|
|
|
|
char message[bufsize];
|
|
|
|
ssize_t recvd = 0, r;
|
|
|
|
uint64_t ino = 42;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
expect_lookup(RELPATH, ino, mode, 0, 1);
|
|
|
|
|
|
|
|
fd = open(FULLPATH, O_RDWR);
|
|
|
|
ASSERT_LE(0, fd) << strerror(errno);
|
2019-04-29 16:24:51 +00:00
|
|
|
ASSERT_EQ(0, pthread_create(&m_child, NULL, writer, &fd))
|
2019-04-29 01:40:35 +00:00
|
|
|
<< strerror(errno);
|
|
|
|
while (recvd < msgsize) {
|
|
|
|
r = read(fd, message + recvd, bufsize - recvd);
|
|
|
|
ASSERT_LE(0, r) << strerror(errno);
|
|
|
|
ASSERT_LT(0, r) << "unexpected EOF";
|
|
|
|
recvd += r;
|
|
|
|
}
|
|
|
|
ASSERT_STREQ(message, MESSAGE);
|
|
|
|
|
2019-06-26 20:25:57 +00:00
|
|
|
leak(fd);
|
2019-04-29 01:40:35 +00:00
|
|
|
}
|
2019-04-29 16:24:51 +00:00
|
|
|
|
|
|
|
/* Writer thread */
|
|
|
|
static void* socket_writer(void* arg __unused) {
|
|
|
|
ssize_t sent = 0;
|
|
|
|
int fd, err;
|
|
|
|
struct sockaddr_un sa;
|
|
|
|
|
|
|
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("socket");
|
|
|
|
return (void*)(intptr_t)errno;
|
|
|
|
}
|
|
|
|
sa.sun_family = AF_UNIX;
|
|
|
|
strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
|
fusefs: coverity cleanup in the tests
Address the following defects reported by Coverity:
* Structurally dead code (CID 1404366): set m_quit before FAIL, not after
* Unchecked return value of sysctlbyname (CID 1404321)
* Unchecked return value of stat(2) (CID 1404471)
* Unchecked return value of open(2) (CID 1404402, 1404529)
* Unchecked return value of dup(2) (CID 1404478)
* Buffer overflows. These are all false positives caused by the fact that
Coverity thinks I'm using a buffer to store strings, when in fact I'm
really just using it to store a byte array that happens to be initialized
with a string. I'm changing the type from char to uint8_t in the hopes
that it will placate Coverity. (CID 1404338, 1404350, 1404367, 1404376,
1404379, 1404381, 1404388, 1404403, 1404425, 1404433, 1404434, 1404474,
1404480, 1404484, 1404503, 1404505)
* False positive file descriptor leak. I'm going to try to fix this with
Coverity modeling, but I'll also change an EXPECT to ASSERT so we don't
perform meaningless assertions after the failure. (CID 1404320, 1404324,
1404440, 1404445).
* Unannotated file descriptor leak. This will be followed up by a Coverity
modeling change. (CID 1404326, 1404334, 1404336, 1404357, 1404361,
1404372, 1404391, 1404395, 1404409, 1404430, 1404448, 1404451, 1404455,
1404457, 1404458, 1404460)
* Uninitialized variables in C++ constructors (CID 1404327, 1404346). In the
case of m_maxphys, this actually led to part of the FUSE_INIT's response
being set to stack garbage during the WriteCluster::clustering test.
* Uninitialized sun_len field in struct sockaddr_un (CID 1404330, 1404371,
1404429).
Reported by: Coverity
Reviewed by: emaste
MFC after: 3 days
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D21457
2019-09-06 19:50:45 +00:00
|
|
|
sa.sun_len = sizeof(FULLPATH);
|
2019-04-29 16:24:51 +00:00
|
|
|
err = connect(fd, (struct sockaddr*)&sa, sizeof(sa));
|
|
|
|
if (err < 0) {
|
|
|
|
perror("connect");
|
|
|
|
return (void*)(intptr_t)errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (sent < msgsize) {
|
|
|
|
ssize_t r;
|
|
|
|
|
|
|
|
r = write(fd, MESSAGE + sent, msgsize - sent);
|
|
|
|
if (r < 0)
|
|
|
|
return (void*)(intptr_t)errno;
|
|
|
|
else
|
|
|
|
sent += r;
|
|
|
|
|
|
|
|
}
|
fusefs: coverity cleanup in the tests
Address the following defects reported by Coverity:
* Structurally dead code (CID 1404366): set m_quit before FAIL, not after
* Unchecked return value of sysctlbyname (CID 1404321)
* Unchecked return value of stat(2) (CID 1404471)
* Unchecked return value of open(2) (CID 1404402, 1404529)
* Unchecked return value of dup(2) (CID 1404478)
* Buffer overflows. These are all false positives caused by the fact that
Coverity thinks I'm using a buffer to store strings, when in fact I'm
really just using it to store a byte array that happens to be initialized
with a string. I'm changing the type from char to uint8_t in the hopes
that it will placate Coverity. (CID 1404338, 1404350, 1404367, 1404376,
1404379, 1404381, 1404388, 1404403, 1404425, 1404433, 1404434, 1404474,
1404480, 1404484, 1404503, 1404505)
* False positive file descriptor leak. I'm going to try to fix this with
Coverity modeling, but I'll also change an EXPECT to ASSERT so we don't
perform meaningless assertions after the failure. (CID 1404320, 1404324,
1404440, 1404445).
* Unannotated file descriptor leak. This will be followed up by a Coverity
modeling change. (CID 1404326, 1404334, 1404336, 1404357, 1404361,
1404372, 1404391, 1404395, 1404409, 1404430, 1404448, 1404451, 1404455,
1404457, 1404458, 1404460)
* Uninitialized variables in C++ constructors (CID 1404327, 1404346). In the
case of m_maxphys, this actually led to part of the FUSE_INIT's response
being set to stack garbage during the WriteCluster::clustering test.
* Uninitialized sun_len field in struct sockaddr_un (CID 1404330, 1404371,
1404429).
Reported by: Coverity
Reviewed by: emaste
MFC after: 3 days
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D21457
2019-09-06 19:50:45 +00:00
|
|
|
|
|
|
|
FuseTest::leak(fd);
|
2019-04-29 16:24:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reading and writing unix-domain sockets works. None of the I/O actually
|
|
|
|
* goes through FUSE.
|
|
|
|
*/
|
|
|
|
TEST_F(Socket, read_write)
|
|
|
|
{
|
|
|
|
mode_t mode = S_IFSOCK | 0755;
|
|
|
|
const int bufsize = 80;
|
|
|
|
char message[bufsize];
|
|
|
|
struct sockaddr_un sa;
|
|
|
|
ssize_t recvd = 0, r;
|
|
|
|
uint64_t ino = 42;
|
|
|
|
int fd, connected;
|
|
|
|
Sequence seq;
|
|
|
|
|
2019-05-31 17:02:37 +00:00
|
|
|
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
|
|
|
|
.WillOnce(Invoke(ReturnErrno(ENOENT)));
|
2019-04-29 16:24:51 +00:00
|
|
|
EXPECT_CALL(*m_mock, process(
|
|
|
|
ResultOf([=](auto in) {
|
2019-05-27 17:08:16 +00:00
|
|
|
return (in.header.opcode == FUSE_MKNOD);
|
2019-04-29 16:24:51 +00:00
|
|
|
}, Eq(true)),
|
|
|
|
_)
|
|
|
|
).InSequence(seq)
|
2019-05-27 17:08:16 +00:00
|
|
|
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
|
2019-05-09 16:25:01 +00:00
|
|
|
SET_OUT_HEADER_LEN(out, entry);
|
2019-05-27 17:08:16 +00:00
|
|
|
out.body.entry.attr.mode = mode;
|
|
|
|
out.body.entry.nodeid = ino;
|
|
|
|
out.body.entry.entry_valid = UINT64_MAX;
|
|
|
|
out.body.entry.attr_valid = UINT64_MAX;
|
2019-04-29 16:24:51 +00:00
|
|
|
})));
|
2019-05-09 16:25:01 +00:00
|
|
|
|
2019-05-31 17:02:37 +00:00
|
|
|
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
|
2019-04-29 16:24:51 +00:00
|
|
|
.InSequence(seq)
|
2019-05-27 17:08:16 +00:00
|
|
|
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
|
2019-04-29 16:24:51 +00:00
|
|
|
SET_OUT_HEADER_LEN(out, entry);
|
2019-05-27 17:08:16 +00:00
|
|
|
out.body.entry.attr.mode = mode;
|
|
|
|
out.body.entry.nodeid = ino;
|
|
|
|
out.body.entry.attr.nlink = 1;
|
|
|
|
out.body.entry.attr_valid = UINT64_MAX;
|
|
|
|
out.body.entry.entry_valid = UINT64_MAX;
|
2019-04-29 16:24:51 +00:00
|
|
|
})));
|
|
|
|
|
|
|
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
ASSERT_LE(0, fd) << strerror(errno);
|
|
|
|
sa.sun_family = AF_UNIX;
|
|
|
|
strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
|
fusefs: coverity cleanup in the tests
Address the following defects reported by Coverity:
* Structurally dead code (CID 1404366): set m_quit before FAIL, not after
* Unchecked return value of sysctlbyname (CID 1404321)
* Unchecked return value of stat(2) (CID 1404471)
* Unchecked return value of open(2) (CID 1404402, 1404529)
* Unchecked return value of dup(2) (CID 1404478)
* Buffer overflows. These are all false positives caused by the fact that
Coverity thinks I'm using a buffer to store strings, when in fact I'm
really just using it to store a byte array that happens to be initialized
with a string. I'm changing the type from char to uint8_t in the hopes
that it will placate Coverity. (CID 1404338, 1404350, 1404367, 1404376,
1404379, 1404381, 1404388, 1404403, 1404425, 1404433, 1404434, 1404474,
1404480, 1404484, 1404503, 1404505)
* False positive file descriptor leak. I'm going to try to fix this with
Coverity modeling, but I'll also change an EXPECT to ASSERT so we don't
perform meaningless assertions after the failure. (CID 1404320, 1404324,
1404440, 1404445).
* Unannotated file descriptor leak. This will be followed up by a Coverity
modeling change. (CID 1404326, 1404334, 1404336, 1404357, 1404361,
1404372, 1404391, 1404395, 1404409, 1404430, 1404448, 1404451, 1404455,
1404457, 1404458, 1404460)
* Uninitialized variables in C++ constructors (CID 1404327, 1404346). In the
case of m_maxphys, this actually led to part of the FUSE_INIT's response
being set to stack garbage during the WriteCluster::clustering test.
* Uninitialized sun_len field in struct sockaddr_un (CID 1404330, 1404371,
1404429).
Reported by: Coverity
Reviewed by: emaste
MFC after: 3 days
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D21457
2019-09-06 19:50:45 +00:00
|
|
|
sa.sun_len = sizeof(FULLPATH);
|
2019-04-29 16:24:51 +00:00
|
|
|
ASSERT_EQ(0, bind(fd, (struct sockaddr*)&sa, sizeof(sa)))
|
|
|
|
<< strerror(errno);
|
|
|
|
listen(fd, 5);
|
|
|
|
ASSERT_EQ(0, pthread_create(&m_child, NULL, socket_writer, NULL))
|
|
|
|
<< strerror(errno);
|
|
|
|
connected = accept(fd, 0, 0);
|
|
|
|
ASSERT_LE(0, connected) << strerror(errno);
|
|
|
|
|
|
|
|
while (recvd < msgsize) {
|
|
|
|
r = read(connected, message + recvd, bufsize - recvd);
|
|
|
|
ASSERT_LE(0, r) << strerror(errno);
|
|
|
|
ASSERT_LT(0, r) << "unexpected EOF";
|
|
|
|
recvd += r;
|
|
|
|
}
|
|
|
|
ASSERT_STREQ(message, MESSAGE);
|
|
|
|
|
2019-06-26 20:25:57 +00:00
|
|
|
leak(fd);
|
2019-04-29 16:24:51 +00:00
|
|
|
}
|