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
|
diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c
index 6012562..87a6aa7 100644
--- a/bsd-user/freebsd/os-sys.c
+++ b/bsd-user/freebsd/os-sys.c
@@ -1,7 +1,7 @@
/*
* FreeBSD sysctl() and sysarch() system call emulation
*
- * Copyright (c) 2013 Stacey D. Son
+ * Copyright (c) 2013-14 Stacey D. Son
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/mount.h>
#include <sys/sysctl.h>
#include <string.h>
@@ -28,6 +29,59 @@
#include "target_os_vmparam.h"
/*
+ * XXX The following should maybe go some place else. Also, see the note
+ * about using "thunk" for sysctl's that pass data using structures.
+ */
+/* From sys/mount.h: */
+#define TARGET_MFSNAMELEN 16 /* length of type name including null */
+struct target_xvfsconf {
+ abi_ulong vfc_vfsops; /* filesystem op vector - not used */
+ char vfc_name[TARGET_MFSNAMELEN]; /* filesystem type name */
+ int32_t vfc_typenum; /* historic fs type number */
+ int32_t vfc_refcount; /* number mounted of this type */
+ int32_t vfc_flags; /* permanent flags */
+ abi_ulong vfc_next; /* next int list - not used */
+};
+
+/* vfc_flag definitions */
+#define TARGET_VFCF_STATIC 0x00010000 /* statically compiled into kernel */
+#define TARGET_VFCF_NETWORK 0x00020000 /* may get data over the network */
+#define TARGET_VFCF_READONLY 0x00040000 /* writes are not implemented */
+#define TARGET_VFCF_SYNTHETIC 0x00080000 /* doesn't represent real files */
+#define TARGET_VFCF_LOOPBACK 0x00100000 /* aliases some other mounted FS */
+#define TARGET_VFCF_UNICODE 0x00200000 /* stores file names as Unicode */
+#define TARGET_VFCF_JAIL 0x00400000 /* can be mounted within a jail */
+#define TARGET_VFCF_DELEGADMIN 0x00800000 /* supports delegated admin */
+#define TARGET_VFCF_SBDRY 0x01000000 /* defer stop requests */
+
+static int
+host_to_target_vfc_flags(int flags)
+{
+ int ret = 0;
+
+ if (flags & VFCF_STATIC)
+ ret |= TARGET_VFCF_STATIC;
+ if (flags & VFCF_NETWORK)
+ ret |= TARGET_VFCF_NETWORK;
+ if (flags & VFCF_READONLY)
+ ret |= TARGET_VFCF_READONLY;
+ if (flags & VFCF_SYNTHETIC)
+ ret |= TARGET_VFCF_SYNTHETIC;
+ if (flags & VFCF_LOOPBACK)
+ ret |= TARGET_VFCF_LOOPBACK;
+ if (flags & VFCF_UNICODE)
+ ret |= TARGET_VFCF_UNICODE;
+ if (flags & VFCF_JAIL)
+ ret |= TARGET_VFCF_JAIL;
+ if (flags & VFCF_DELEGADMIN)
+ ret |= TARGET_VFCF_DELEGADMIN;
+ if (flags & VFCF_SBDRY)
+ ret |= TARGET_VFCF_SBDRY;
+
+ return ret;
+}
+
+/*
* XXX this uses the undocumented oidfmt interface to find the kind of
* a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
* (compare to src/sbin/sysctl/sysctl.c)
@@ -161,6 +215,7 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
oidfmt(snamep, namelen, NULL, &kind);
/* Handle some arch/emulator dependent sysctl()'s here. */
+ /* XXX sysctl()'s that pass structs should use thunk like ioctl(). */
switch (snamep[0]) {
case CTL_KERN:
switch (snamep[1]) {
@@ -212,6 +267,63 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
}
break;
+ case CTL_VFS:
+ {
+ static int oid_vfs_conflist;
+
+ if (!oid_vfs_conflist) {
+ int real_oid[CTL_MAXNAME+2];
+ size_t len = sizeof(real_oid) / sizeof(int);
+
+ if (sysctlnametomib("vfs.conflist", real_oid, &len) >= 0)
+ oid_vfs_conflist = real_oid[1];
+ }
+
+ if (oid_vfs_conflist && snamep[1] == oid_vfs_conflist) {
+ struct xvfsconf *xvfsp;
+ struct target_xvfsconf *txp;
+ int cnt, i;
+
+ if (sysctlbyname("vfs.conflist", NULL, &holdlen, NULL, 0) < 0) {
+ ret = -1;
+ goto out;
+ }
+ cnt = holdlen / sizeof(struct xvfsconf);
+ if (!holdp) {
+ holdlen = cnt * sizeof(struct target_xvfsconf);
+ ret = 0;
+ goto out;
+ }
+ xvfsp = (struct xvfsconf *)g_malloc(holdlen);
+ if (xvfsp == NULL) {
+ ret = -TARGET_ENOMEM;
+ goto out;
+ }
+ if (sysctlbyname("vfs.conflist", xvfsp, &holdlen, NULL, 0) < 0){
+ g_free(xvfsp);
+ ret = -1;
+ goto out;
+ }
+ cnt = holdlen / sizeof(struct xvfsconf);
+ holdlen = cnt * sizeof(struct target_xvfsconf);
+ txp = (struct target_xvfsconf *)holdp;
+ for (i = 0; i < cnt; i++) {
+ txp[i].vfc_vfsops = 0;
+ strlcpy(txp[i].vfc_name, xvfsp[i].vfc_name,
+ TARGET_MFSNAMELEN);
+ txp[i].vfc_typenum = tswap32(xvfsp[i].vfc_typenum);
+ txp[i].vfc_refcount = tswap32(xvfsp[i].vfc_refcount);
+ txp[i].vfc_flags = tswap32(
+ host_to_target_vfc_flags(xvfsp[i].vfc_flags));
+ txp[i].vfc_next = 0;
+ }
+ g_free(xvfsp);
+ ret = 0;
+ goto out;
+ }
+ }
+ break;
+
case CTL_HW:
switch (snamep[1]) {
case HW_MACHINE:
|