Refactored and unit-tested filter_special_opts. Shaved a bunch of yaks on the way.

alpine-vm-issue106
Martin Pärtel 2 years ago
parent 2cf41a75c1
commit bc5313dc58
  1. 10
      configure.ac
  2. 4
      src/Makefile.am
  3. 50
      src/arena.c
  4. 15
      src/arena.h
  5. 150
      src/bindfs.c
  6. 107
      src/misc.c
  7. 25
      src/misc.h
  8. 1
      src/userinfo.c
  9. 2
      tests/internals/Makefile.am
  10. 183
      tests/internals/test_internals.c
  11. 6
      tests/test_bindfs.rb
  12. 5
      tests/utimens_nofollow.c
  13. 2
      vagrant/debian10/Vagrantfile
  14. 2
      vagrant/debian9/Vagrantfile
  15. 7
      vagrant/freebsd12/Vagrantfile

@ -28,8 +28,14 @@ fi
AM_CONDITIONAL(BUILD_OS_IS_DARWIN, [test x"$build_os" = darwin])
my_CPPFLAGS="-D_REENTRANT -D_FILE_OFFSET_BITS=64"
my_CFLAGS="-Wall -fno-common"
# _XOPEN_SOURCE is >= 500 for pread/pwrite; >= 700 for utimensat.
# __BSD_VISIBLE is for flock() on FreeBSD. It otherwise gets hidden by _XOPEN_SOURCE.
# _BSD_SOURCE is for stat() nanosecond precision and lutimes().
# _DEFAULT_SOURCE is the new non-deprecated version of _BSD_SOURCE.
# _DARWIN_BETTER_REALPATH fixes MacOS realpath() broken around Catalina (#83).
my_CPPFLAGS="-D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700 -D__BSD_VISIBLE=1 -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_DARWIN_BETTER_REALPATH"
my_CFLAGS="-Wall -fno-common -std=c99"
my_LDFLAGS="-pthread"
AC_SUBST([my_CPPFLAGS])
AC_SUBST([my_CFLAGS])

@ -2,8 +2,8 @@
bin_PROGRAMS = bindfs
noinst_HEADERS = debug.h permchain.h userinfo.h misc.h usermap.h rate_limiter.h
bindfs_SOURCES = bindfs.c debug.c permchain.c userinfo.c misc.c usermap.c rate_limiter.c
noinst_HEADERS = debug.h permchain.h userinfo.h arena.h misc.h usermap.h rate_limiter.h
bindfs_SOURCES = bindfs.c debug.c permchain.c userinfo.c arena.c misc.c usermap.c rate_limiter.c
AM_CPPFLAGS = ${my_CPPFLAGS} ${fuse_CFLAGS} ${fuse3_CFLAGS}
AM_CFLAGS = ${my_CFLAGS}

@ -0,0 +1,50 @@
#include "arena.h"
struct block {
size_t size;
size_t used;
struct block *next;
char data_start[];
};
static const size_t min_block_room = 16 * 1024 - sizeof(struct block);
static void add_block(struct arena* a, size_t room_wanted)
{
if (room_wanted < min_block_room) {
room_wanted = min_block_room;
}
struct block *new_block = malloc(sizeof(struct block) + room_wanted);
new_block->size = room_wanted;
new_block->used = 0;
new_block->next = a->cur_block;
a->cur_block = new_block;
}
void arena_init(struct arena *a)
{
a->cur_block = NULL;
}
void* arena_malloc(struct arena *a, size_t amount)
{
struct block* b = a->cur_block;
if (b == NULL || b->size - b->used < amount) {
add_block(a, amount);
b = a->cur_block;
}
void* result = &b->data_start[b->used];
b->used += amount;
return result;
}
void arena_free(struct arena *a)
{
struct block* b = a->cur_block;
while (b != NULL) {
struct block* next = b->next;
free(b);
b = next;
}
a->cur_block = NULL;
}

@ -0,0 +1,15 @@
#ifndef INC_BINDFS_ARENA_H
#define INC_BINDFS_ARENA_H
#include <stdlib.h>
struct block;
struct arena {
struct block *cur_block;
};
void arena_init(struct arena *a);
void* arena_malloc(struct arena *a, size_t amount);
void arena_free(struct arena *a);
#endif

@ -31,20 +31,6 @@
#include <config.h>
/* For >= 500 for pread/pwrite; >= 700 for utimensat */
#define _XOPEN_SOURCE 700
/* For flock() on FreeBSD. It otherwise gets hidden by _XOPEN_SOURCE */
#define __BSD_VISIBLE 1
/* For stat() nanosecond precision and lutimes() */
#define _BSD_SOURCE
/* The new non-deprecated version of _BSD_SOURCE */
#define _DEFAULT_SOURCE
/* Fix MacOS realpath() broken around Catalina (#83) */
#define _DARWIN_BETTER_REALPATH
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
@ -97,6 +83,7 @@
#include <fuse.h>
#include <fuse_opt.h>
#include "arena.h"
#include "debug.h"
#include "misc.h"
#include "permchain.h"
@ -367,6 +354,7 @@ Why? Because some of those options like "nofail"
are special ones interpreted by systemd in /etc/fstab
*/
struct fuse_args filter_special_opts(struct fuse_args *args);
static bool keep_option(const char* opt);
static int is_mirroring_enabled()
{
@ -2085,8 +2073,8 @@ static int parse_map_file(UserMap *map, UserMap *reverse_map, char *file, int as
UsermapStatus status;
// Toggle between UID (passwd) and GID (group)
const int (*value_to_id)(const char *username, uid_t *ret);
const UsermapStatus (*usermap_add)(UserMap *map, uid_t from, uid_t to);
int (*value_to_id)(const char *username, uid_t *ret);
UsermapStatus (*usermap_add)(UserMap *map, uid_t from, uid_t to);
const char *label_name, *label_id;
if (as_gid) {
value_to_id = &group_gid;
@ -2336,11 +2324,27 @@ static void atexit_func()
struct fuse_args filter_special_opts(struct fuse_args *args)
{
bool ignore;
struct arena arena;
arena_init(&arena);
int tmp_argc = args->argc;
char **tmp_argv;
filter_o_opts(&keep_option, args->argc, (const char * const *)args->argv, &tmp_argc, &tmp_argv, &arena);
struct fuse_args new_args = FUSE_ARGS_INIT(0, (void*)0);
for (int i = 0; i < tmp_argc; i++) {
fuse_opt_add_arg(&new_args, tmp_argv[i]);
}
arena_free(&arena);
fuse_opt_free_args(args);
return new_args;
}
static bool keep_option(const char* opt)
{
// Copied from "libfuse/util/mount.fuse.c" (fuse-3.10.1)
const char *ignore_opts[] = {
static const char * const ignored_opts[] = {
"",
"user",
"nofail",
@ -2352,114 +2356,12 @@ struct fuse_args filter_special_opts(struct fuse_args *args)
NULL
};
for (int i = 0; i < args->argc; i++) {
ignore = false;
/* If current element is exactly "-o" modify/check the following element */
if (strcmp(args->argv[i], "-o") == 0 && (i+1) < args->argc) {
/* remove ignored option from a comma separated list */
if (strchr(args->argv[i+1], ',') != NULL) {
char *tmpStr = (char*) calloc(strlen(args->argv[i+1]) + 1, sizeof(char));
char *ptr = strtok(args->argv[i+1], ",");
while (ptr != NULL) {
ignore = false;
for (int j = 0; ignore_opts[j]; j++) {
if (strcmp(ptr, ignore_opts[j]) == 0) {
ignore = true;
break;
}
}
if (!ignore) {
if (strlen(tmpStr) > 0) strcat(tmpStr, ",");
strcat(tmpStr, ptr);
}
ptr = strtok(NULL, ",");
}
if (strlen(tmpStr) > 0) {
args->argv[i+1] = (char*) calloc(strlen(tmpStr) + 1, sizeof(char));
strcpy(args->argv[i+1], tmpStr);
free(tmpStr);
ignore = false;
}
else {
ignore = true;
++i;
}
}
/* ignore this and the following element if it has exactly the ignored option */
else {
for (int j = 0; ignore_opts[j]; j++) {
if (strcmp(args->argv[i+1], ignore_opts[j]) == 0) {
ignore = true;
++i;
break;
}
}
}
}
/* else if element starts with "-o" */
else if (strncmp(args->argv[i], "-o", 2) == 0) {
/* remove ignored option from a comma seperated list */
if (strchr(args->argv[i], ',') != NULL) {
char *tmpStr = (char*) calloc(strlen(args->argv[i]) + 1, sizeof(char));
char *tmpStr2 = (char*) calloc(strlen(args->argv[i]) + 1 - 2, sizeof(char));
// remove first 2 chars from args->argv[i] and save this to tmpStr2
memcpy(tmpStr2, args->argv[i] + 2, strlen(args->argv[i]) - 2);
char *ptr = strtok(tmpStr2, ",");
while (ptr != NULL) {
ignore = false;
for (int j = 0; ignore_opts[j]; j++) {
if (strcmp(ptr, ignore_opts[j]) == 0) {
ignore = true;
break;
}
}
if (!ignore) {
if (strlen(tmpStr) > 0) strcat(tmpStr, ",");
strcat(tmpStr, ptr);
}
ptr = strtok(NULL, ",");
}
if (strlen(tmpStr) > 0) {
args->argv[i] = (char*) calloc(2 + strlen(tmpStr) + 1, sizeof(char));
strcat(args->argv[i], "-o");
strcat(args->argv[i], tmpStr);
free(tmpStr);
free(tmpStr2);
ignore = false;
}
else {
ignore = true;
}
}
/* ignore this element if it has exactly the ignored option */
else {
for (int j = 0; ignore_opts[j]; j++) {
char* tmpStr = (char*) calloc(2 + strlen(ignore_opts[j]) + 1, sizeof(char));
strcat(tmpStr, "-o");
strcat(tmpStr, ignore_opts[j]);
if (strcmp(args->argv[i], tmpStr) == 0) {
ignore = true;
free(tmpStr);
break;
}
free(tmpStr);
}
}
}
if (!ignore) {
fuse_opt_add_arg(&new_args, strdup(args->argv[i]));
for (int i = 0; ignored_opts[i] != NULL; ++i) {
if (strcmp(ignored_opts[i], opt) == 0) {
return false;
}
}
fuse_opt_free_args(args);
return new_args;
return true;
}
int main(int argc, char *argv[])

@ -135,6 +135,102 @@ const char *my_dirname(char *path)
}
}
static char **dup_argv(int argc, const char * const *argv, struct arena *arena)
{
char **pointer_list = arena_malloc(arena, (argc + 1) * sizeof(char*));
char **next_ptr = pointer_list;
for (int i = 0; i < argc; ++i) {
int len = strlen(argv[i]);
char *str = arena_malloc(arena, len + 1);
memcpy(str, argv[i], len + 1);
*next_ptr = str;
++next_ptr;
}
*next_ptr = NULL;
return pointer_list;
}
/* Converts all ("-o", "...") into ("-o..."). */
static void merge_o_args(
int *argc,
char **argv,
struct arena *arena
)
{
int i = 0;
while (i < *argc) {
char *arg = argv[i];
if (strcmp(arg, "-o") == 0) {
if (i + 1 < *argc) {
char *merged = arena_malloc(arena, 2 + strlen(argv[i + 1]) + 1);
merged[0] = '-';
merged[1] = 'o';
strcpy(&merged[2], argv[i + 1]);
argv[i] = merged;
for (int j = i + 1; j < *argc - 1; ++j) {
argv[j] = argv[j + 1];
}
}
--*argc;
}
++i;
}
}
void filter_o_opts(
bool (*keep)(const char* opt),
int orig_argc,
const char * const *orig_argv,
int *new_argc,
char ***new_argv,
struct arena* arena
)
{
int argc = orig_argc;
char **argv = dup_argv(argc, orig_argv, arena);
merge_o_args(&argc, argv, arena);
for (int i = 0; i < argc; i++) {
char *arg = argv[i];
if (strncmp(arg, "-o", 2) == 0) {
char *filtered = arena_malloc(arena, strlen(arg) + 1);
char *filtered_end = filtered;
const char *tok = strtok(arg + 2, ",");
while (tok != NULL) {
size_t tok_len = strlen(tok);
if ((*keep)(tok)) {
if (filtered_end == filtered) {
*(filtered_end++) = '-';
*(filtered_end++) = 'o';
} else {
*(filtered_end++) = ',';
}
memcpy(filtered_end, tok, tok_len + 1);
filtered_end += tok_len; // We'll overwrite the null terminator if we append more.
}
tok = strtok(NULL, ",");
}
if (filtered != filtered_end) {
argv[i] = filtered;
} else {
for (int j = i; j < argc - 1; ++j) {
argv[j] = argv[j + 1];
}
--argc;
}
}
}
*new_argc = argc;
*new_argv = argv;
}
void grow_array_impl(void **array, int *capacity, int member_size)
{
int new_cap = *capacity;
@ -170,7 +266,8 @@ int parse_byte_count(const char *str, double *result)
return 1;
}
void init_memory_block(struct memory_block *a, int initial_capacity)
void init_memory_block(struct memory_block *a, size_t initial_capacity)
{
a->size = 0;
a->capacity = initial_capacity;
@ -181,9 +278,9 @@ void init_memory_block(struct memory_block *a, int initial_capacity)
}
}
void grow_memory_block(struct memory_block *a, int amount)
void grow_memory_block(struct memory_block *a, size_t amount)
{
int new_cap;
size_t new_cap;
a->size += amount;
if (a->size >= a->capacity) {
@ -204,9 +301,9 @@ void grow_memory_block(struct memory_block *a, int amount)
}
}
int append_to_memory_block(struct memory_block *a, void *src, int src_size)
int append_to_memory_block(struct memory_block *a, const void *src, size_t src_size)
{
int dest = a->size;
size_t dest = a->size;
grow_memory_block(a, src_size);
memcpy(&a->ptr[dest], src, src_size);
return dest;

@ -20,6 +20,10 @@
#ifndef INC_BINDFS_MISC_H
#define INC_BINDFS_MISC_H
#include <stdbool.h>
#include <stdlib.h>
#include "arena.h"
/* Counts the number of times ch occurs in s. */
int count_chars(const char *s, char ch);
@ -49,6 +53,17 @@ const char *my_basename(const char *path);
Otherwise, returns ".". */
const char *my_dirname(char *path);
/* Filters arguments in comma-separated lists prefixed by '-o'.
* Allocates 'new_argv' and its strings, as well as some temporary data, into 'arena'. */
void filter_o_opts(
bool (*keep)(const char* opt),
int argc,
const char * const *argv,
int *new_argc,
char ***new_argv,
struct arena *arena
);
/* Reallocs `*array` (may be NULL) to be at least one larger
than `*capacity` (may be 0) and stores the new capacity
in `*capacity`. */
@ -62,15 +77,15 @@ int parse_byte_count(const char *str, double *result);
growing it and appending to it. */
struct memory_block {
char *ptr;
int size;
int capacity;
size_t size;
size_t capacity;
};
#define MEMORY_BLOCK_INITIALIZER { NULL, 0, 0 }
void init_memory_block(struct memory_block *a, int initial_capacity);
void grow_memory_block(struct memory_block *a, int amount);
int append_to_memory_block(struct memory_block *a, void *src, int src_size);
void init_memory_block(struct memory_block *a, size_t initial_capacity);
void grow_memory_block(struct memory_block *a, size_t amount);
int append_to_memory_block(struct memory_block *a, const void *src, size_t src_size);
void free_memory_block(struct memory_block *a);
#define MEMORY_BLOCK_GET(a, offset) (&(a).ptr[(offset)])

@ -20,6 +20,7 @@
#include "userinfo.h"
#include "misc.h"
#include "debug.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>

@ -1,7 +1,7 @@
noinst_HEADERS = test_common.h
noinst_PROGRAMS = test_internals test_rate_limiter
test_internals_SOURCES = test_internals.c test_common.c $(top_srcdir)/src/misc.c
test_internals_SOURCES = test_internals.c test_common.c $(top_srcdir)/src/misc.c $(top_srcdir)/src/arena.c
test_rate_limiter_SOURCES = test_rate_limiter.c test_common.c $(top_srcdir)/src/rate_limiter.c
test_internals_CPPFLAGS = ${my_CPPFLAGS} ${fuse_CFLAGS} ${fuse3_CFLAGS} -I. -I$(top_srcdir)/src

@ -1,10 +1,40 @@
#define _XOPEN_SOURCE 700
#include "test_common.h"
#include "misc.h"
#include <string.h>
#include <stdlib.h>
void test_my_dirname(char *arg, const char *expected)
static void arena_suite()
{
const int iterations = 1000;
struct arena arena;
int** pointers = calloc(iterations, sizeof(int*));
arena_init(&arena);
for (int i = 0; i < iterations; ++i) {
int count = 17 * i;
int* p = arena_malloc(&arena, count * sizeof(int));
pointers[i] = p;
for (int j = 0; j < count; ++j) {
p[j] = j;
}
}
for (int i = 0; i < iterations; ++i) {
int count = 17 * i;
int* p = pointers[i];
for (int j = 0; j < count; ++j) {
TEST_ASSERT(p[j] == j);
}
}
arena_free(&arena);
free(pointers);
}
static void test_my_dirname(char *arg, const char *expected)
{
char *orig = strdup(arg);
@ -17,7 +47,7 @@ void test_my_dirname(char *arg, const char *expected)
free(orig);
}
void my_dirname_suite()
static void my_dirname_suite()
{
char buf[256];
@ -52,7 +82,7 @@ void my_dirname_suite()
test_my_dirname(buf, "..");
}
void sprintf_new_suite() {
static void sprintf_new_suite() {
char *result;
result = sprintf_new("Hello %d %s", 123, "World");
@ -64,9 +94,154 @@ void sprintf_new_suite() {
free(result);
}
void test_internal_suite() {
static int arg_count(const char **argv)
{
int i = 0;
while (argv[i] != NULL) {
++i;
}
return i;
}
static bool keep_opt(const char *opt) {
return *opt != '\0' && strncmp(opt, "bad", 3) != 0;
}
static char *join_args(int argc, const char** argv) {
struct memory_block block = MEMORY_BLOCK_INITIALIZER;
for (int i = 0; i < argc; ++i) {
int len = strlen(argv[i]);
append_to_memory_block(&block, argv[i], len);
if (i + 1 < argc) {
append_to_memory_block(&block, " ", 1);
} else {
append_to_memory_block(&block, "\0", 1);
}
}
return block.ptr;
}
static void filter_o_opts_test(const char **init, const char **expected) {
int argc = arg_count(init);
char *joined_input = join_args(argc, init);
struct arena arena;
arena_init(&arena);
char **argv;
filter_o_opts(keep_opt, argc, init, &argc, &argv, &arena);
for (int i = 0; i < argc; ++i) {
if (argv[i] == NULL) {
printf("Expected %s but got end of argv at index %d with input %s\n", expected[i], i, joined_input);
failures++;
break;
}
if (expected[i] == NULL) {
printf("Expected end of args but got %s at index %d with input %s\n", argv[i], i, joined_input);
failures++;
break;
}
if (strcmp(argv[i], expected[i]) != 0) {
printf("Expected %s but got %s at index %d with input %s\n", expected[i], argv[i], i, joined_input);
failures++;
break;
}
}
arena_free(&arena);
free(joined_input);
}
static void filter_o_opts_suite() {
{
const char *in[] = {"-obad1", NULL};
const char *exp[] = {NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-ogood1", NULL};
const char *exp[] = {"-ogood1", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-obad1,good1", NULL};
const char *exp[] = {"-ogood1", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-ogood1,bad", NULL};
const char *exp[] = {"-ogood1", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-obad1,good1,bad2", NULL};
const char *exp[] = {"-ogood1", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-obad1,good1,bad2,good2", NULL};
const char *exp[] = {"-ogood1,good2", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-ogood1,bad1,good2", NULL};
const char *exp[] = {"-ogood1,good2", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-o", "bad1", NULL};
const char *exp[] = {NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-o", "good1", NULL};
const char *exp[] = {"-ogood1", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-o", "good1,bad1,good2", NULL};
const char *exp[] = {"-ogood1,good2", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-o", "bad1,good1,bad2", NULL};
const char *exp[] = {"-ogood1", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"unrelated1", "-o", "bad1,good1,bad2", "unrelated2", NULL};
const char *exp[] = {"unrelated1", "-ogood1", "unrelated2", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"unrelated1", "-o", ",,,bad1,,good1,,bad2,,,", "unrelated2", NULL};
const char *exp[] = {"unrelated1", "-ogood1", "unrelated2", NULL};
filter_o_opts_test(in, exp);
}
{
const char *in[] = {"-o", NULL};
const char *exp[] = {NULL};
filter_o_opts_test(in, exp);
}
}
static void test_internal_suite() {
arena_suite();
my_dirname_suite();
sprintf_new_suite();
filter_o_opts_suite();
}
TEST_MAIN(test_internal_suite);

@ -296,7 +296,9 @@ testenv("--chmod-deny --chmod-allow-x") do
assert_exception(EPERM) { chmod(0777, 'mnt/file') }
assert_exception(EPERM) { chmod(0000, 'mnt/file') }
assert_exception(EPERM) { chmod(01700, 'mnt/file') } # sticky bit
if `uname`.strip != 'FreeBSD' # FreeBSD doesn't let us set the sticky bit on files
assert_exception(EPERM) { chmod(01700, 'mnt/file') } # sticky bit
end
chmod(0611, 'mnt/file') # chmod that only changes x-bits should work
assert { File.stat('src/file').mode & 07777 == 00611 }
@ -895,7 +897,7 @@ if `uname`.strip != 'FreeBSD' # -o dev is not supported on FreeBSD
end
# PR #95
testenv("-ouser -onofail,nouser,delete-deny -o users -o auto,rename-deny,noauto -o chmod-deny,_netdev", :title => "filtering special options") do
testenv("-ouser -onofail,nouser,,,delete-deny -o users -o auto,rename-deny,noauto -o chmod-deny,_netdev,,", :title => "filtering special options") do
touch('src/file')
assert_exception(EPERM) { rm('mnt/file') }
assert_exception(EPERM) { File.rename('mnt/file', 'mnt/file2') }

@ -1,9 +1,4 @@
/* For atoll and lutimes */
#define _BSD_SOURCE
/* The new non-deprecated version of _BSD_SOURCE */
#define _DEFAULT_SOURCE
#include <config.h>
#include <stdlib.h>
#include <stdio.h>

@ -16,8 +16,8 @@ Vagrant.configure("2") do |config|
end
config.vm.provision "shell", reboot: true, inline: <<-SHELL
export DEBIAN_FRONTEND='noninteractive'
apt-get update
DEBIAN_FRONTEND='noninteractive' apt-get dist-upgrade -y -o Dpkg::Options::="--force-confdef"
apt-get install -y fuse3 libfuse3-dev build-essential pkg-config ruby valgrind
apt-get clean
echo user_allow_other > /etc/fuse.conf

@ -16,8 +16,8 @@ Vagrant.configure("2") do |config|
end
config.vm.provision "shell", reboot: true, inline: <<-SHELL
export DEBIAN_FRONTEND='noninteractive'
apt-get update
DEBIAN_FRONTEND='noninteractive' apt-get dist-upgrade -y -o Dpkg::Options::="--force-confdef"
apt-get install -y fuse libfuse-dev build-essential pkg-config ruby valgrind
apt-get clean
echo user_allow_other > /etc/fuse.conf

@ -2,8 +2,7 @@
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
#config.vm.box = "freebsd/FreeBSD-11.0-STABLE" # doesn't set base_mac so can't use NAT networking :(
config.vm.box = "bento/freebsd-10.3"
config.vm.box = "roboxes/freebsd12"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "../../", "/bindfs",
@ -13,12 +12,12 @@ Vagrant.configure("2") do |config|
rsync__args: ["-av", "--delete-after"]
config.vm.provider "virtualbox" do |v|
v.name = "bindfs-freebsd10_3"
v.name = "bindfs-freebsd12"
end
config.vm.provision "shell", inline: <<-SHELL
pkg update
pkg install -y fusefs-libs pkgconf ruby valgrind
pkg install -y fusefs-libs pkgconf ruby
kldload fuse.ko
echo 'fuse_load="YES"' >> /boot/loader.conf
Loading…
Cancel
Save