16 |
along with this program; if not, write to the Free Software |
along with this program; if not, write to the Free Software |
17 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
18 |
|
|
|
#include <hurd/netfs.h> |
|
19 |
#include <stdio.h> |
#include <stdio.h> |
20 |
#include <stdlib.h> |
#include <stdlib.h> |
21 |
#include <stddef.h> |
#include <stddef.h> |
22 |
#include <unistd.h> |
#include <unistd.h> |
23 |
|
|
24 |
#include <argp.h> |
#include <argp.h> |
25 |
|
#include <argz.h> |
26 |
#include <error.h> |
#include <error.h> |
27 |
#include <string.h> |
#include <string.h> |
28 |
#include <fcntl.h> |
#include <fcntl.h> |
29 |
#include <dirent.h> |
#include <dirent.h> |
30 |
#include <sys/mman.h> |
#include <sys/mman.h> |
31 |
#include <sys/stat.h> |
#include <sys/stat.h> |
32 |
|
#include <rwlock.h> |
33 |
|
#include <maptime.h> |
34 |
#include <cthreads.h> |
#include <cthreads.h> |
|
#include <mcheck.h> |
|
35 |
|
|
36 |
#include <version.h> |
#include <version.h> |
37 |
|
|
38 |
#include "console.h" |
#include <hurd/netfs.h> |
39 |
|
|
40 |
#include "display.h" |
#include "display.h" |
41 |
#include "input.h" |
#include "input.h" |
42 |
|
|
46 |
char *netfs_server_version = HURD_VERSION; |
char *netfs_server_version = HURD_VERSION; |
47 |
int netfs_maxsymlinks = 16; /* Arbitrary. */ |
int netfs_maxsymlinks = 16; /* Arbitrary. */ |
48 |
|
|
49 |
|
/* Handy source of time. */ |
50 |
|
volatile struct mapped_time_value *console_maptime; |
51 |
|
|
52 |
|
#define DEFAULT_ENCODING "ISO-8859-1" |
53 |
|
|
54 |
|
|
55 |
struct vcons |
struct vcons |
56 |
{ |
{ |
75 |
struct node *disp_node; |
struct node *disp_node; |
76 |
struct node *inpt_node; |
struct node *inpt_node; |
77 |
}; |
}; |
78 |
|
/* A handle for a virtual console device. */ |
79 |
|
typedef struct vcons *vcons_t; |
80 |
|
|
81 |
struct cons |
struct cons |
82 |
{ |
{ |
83 |
/* The lock protects the console, all virtual consoles contained in |
/* The lock protects the console, all virtual consoles contained in |
84 |
it and the reference counters. It also locks the |
it and the reference counters. It also locks the configuration |
85 |
configuration. */ |
parameters. */ |
86 |
struct mutex lock; |
struct mutex lock; |
87 |
vcons_t vcons_list; |
vcons_t vcons_list; |
88 |
/* The encoding. */ |
/* The encoding. */ |
89 |
const char *encoding; |
char *encoding; |
90 |
|
|
91 |
struct node *node; |
struct node *node; |
92 |
mach_port_t underlying; |
mach_port_t underlying; |
93 |
/* A template for the stat information of all nodes. */ |
/* A template for the stat information of all nodes. */ |
94 |
struct stat stat_template; |
struct stat stat_template; |
95 |
} mycons; |
}; |
96 |
cons_t cons = &mycons; |
/* A handle for a console device. */ |
97 |
|
typedef struct cons *cons_t; |
98 |
|
|
99 |
|
|
100 |
/* Lookup the virtual console with number ID in the console CONS, |
/* Lookup the virtual console with number ID in the console CONS, |
101 |
acquire a reference for it, and return it in R_VCONS. If CREATE is |
acquire a reference for it, and return it in R_VCONS. If CREATE is |
102 |
true, the virtual console will be created if it doesn't exist yet. |
true, the virtual console will be created if it doesn't exist yet. |
161 |
/* XXX Error checking. */ |
/* XXX Error checking. */ |
162 |
|
|
163 |
mutex_init (&vcons->lock); |
mutex_init (&vcons->lock); |
164 |
err = display_create (&vcons->display, cons->encoding); |
err = display_create (&vcons->display, cons->encoding ?: DEFAULT_ENCODING); |
165 |
if (err) |
if (err) |
166 |
{ |
{ |
167 |
free (vcons->name); |
free (vcons->name); |
170 |
return err; |
return err; |
171 |
} |
} |
172 |
|
|
173 |
err = input_create (&vcons->input, cons->encoding); |
err = input_create (&vcons->input, cons->encoding ?: DEFAULT_ENCODING); |
174 |
if (err) |
if (err) |
175 |
{ |
{ |
176 |
display_destroy (vcons->display); |
display_destroy (vcons->display); |
279 |
free (nn); |
free (nn); |
280 |
return ENOMEM; |
return ENOMEM; |
281 |
} |
} |
282 |
(*np)->nn_stat = cons->stat_template; |
(*np)->nn_stat = vcons->cons->stat_template; |
283 |
(*np)->nn_translated = 0; |
(*np)->nn_translated = 0; |
284 |
|
|
285 |
switch (type) |
switch (type) |
299 |
(*np)->nn_stat.st_ino = (vcons->id << 2) + 2; |
(*np)->nn_stat.st_ino = (vcons->id << 2) + 2; |
300 |
(*np)->nn_stat.st_mode |= S_IFREG; |
(*np)->nn_stat.st_mode |= S_IFREG; |
301 |
(*np)->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); |
(*np)->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); |
302 |
(*np)->nn_stat.st_size = 2008 * sizeof (wchar_t); /* XXX */ |
(*np)->nn_stat.st_size = 2011 * sizeof (wchar_t); /* XXX */ |
303 |
break; |
break; |
304 |
case VCONS_NODE_INPUT: |
case VCONS_NODE_INPUT: |
305 |
(*np)->nn_stat.st_ino = (vcons->id << 2) + 3; |
(*np)->nn_stat.st_ino = (vcons->id << 2) + 3; |
311 |
|
|
312 |
/* If the underlying node isn't a directory, propagate read permission to |
/* If the underlying node isn't a directory, propagate read permission to |
313 |
execute permission since we need that for lookups. */ |
execute permission since we need that for lookups. */ |
314 |
if (! S_ISDIR (cons->stat_template.st_mode) |
if (! S_ISDIR (vcons->cons->stat_template.st_mode) |
315 |
&& S_ISDIR ((*np)->nn_stat.st_mode)) |
&& S_ISDIR ((*np)->nn_stat.st_mode)) |
316 |
{ |
{ |
317 |
if (cons->stat_template.st_mode & S_IRUSR) |
if (vcons->cons->stat_template.st_mode & S_IRUSR) |
318 |
(*np)->nn_stat.st_mode |= S_IXUSR; |
(*np)->nn_stat.st_mode |= S_IXUSR; |
319 |
if (cons->stat_template.st_mode & S_IRGRP) |
if (vcons->cons->stat_template.st_mode & S_IRGRP) |
320 |
(*np)->nn_stat.st_mode |= S_IXGRP; |
(*np)->nn_stat.st_mode |= S_IXGRP; |
321 |
if (cons->stat_template.st_mode & S_IROTH) |
if (vcons->cons->stat_template.st_mode & S_IROTH) |
322 |
(*np)->nn_stat.st_mode |= S_IXOTH; |
(*np)->nn_stat.st_mode |= S_IXOTH; |
323 |
} |
} |
324 |
|
|
1048 |
else |
else |
1049 |
{ |
{ |
1050 |
/* Pass display content to caller. */ |
/* Pass display content to caller. */ |
1051 |
ssize_t amt; |
ssize_t amt = *len; |
1052 |
assert (np == vcons->disp_node); |
assert (np == vcons->disp_node); |
1053 |
amt = display_read (vcons->display, |
|
1054 |
/* cred->po->openstat & O_NONBLOCK */ 0, |
if (amt > np->nn_stat.st_size) |
1055 |
offset, data, *len); |
amt = np->nn_stat.st_size; |
1056 |
|
amt = display_read (vcons->display, |
1057 |
|
/* cred->po->openstat & O_NONBLOCK */ 0, |
1058 |
|
offset, data, amt); |
1059 |
if (amt == -1) |
if (amt == -1) |
1060 |
err = errno; |
err = errno; |
1061 |
else |
else |
1108 |
} |
} |
1109 |
|
|
1110 |
|
|
1111 |
|
/* Implement io_map as described in <hurd/io.defs>. */ |
1112 |
|
kern_return_t |
1113 |
|
netfs_S_io_map (struct protid *cred, |
1114 |
|
memory_object_t *rdobj, |
1115 |
|
mach_msg_type_name_t *rdtype, |
1116 |
|
memory_object_t *wrobj, |
1117 |
|
mach_msg_type_name_t *wrtype) |
1118 |
|
{ |
1119 |
|
int flags; |
1120 |
|
struct node *np; |
1121 |
|
vcons_t vcons; |
1122 |
|
|
1123 |
|
if (!cred) |
1124 |
|
return EOPNOTSUPP; |
1125 |
|
|
1126 |
|
np = cred->po->np; |
1127 |
|
vcons = np->nn->vcons; |
1128 |
|
if (!vcons || np != vcons->disp_node) |
1129 |
|
return EOPNOTSUPP; |
1130 |
|
|
1131 |
|
*wrobj = *rdobj = MACH_PORT_NULL; |
1132 |
|
|
1133 |
|
flags = cred->po->openstat & (O_READ | O_WRITE); |
1134 |
|
|
1135 |
|
mutex_lock (&np->lock); |
1136 |
|
switch (flags) |
1137 |
|
{ |
1138 |
|
case O_READ | O_WRITE: |
1139 |
|
*wrobj = *rdobj = display_get_filemap (vcons->display, |
1140 |
|
VM_PROT_READ | VM_PROT_WRITE); |
1141 |
|
if (*wrobj == MACH_PORT_NULL) |
1142 |
|
goto error; |
1143 |
|
mach_port_mod_refs (mach_task_self (), *rdobj, MACH_PORT_RIGHT_SEND, 1); |
1144 |
|
break; |
1145 |
|
case O_READ: |
1146 |
|
*rdobj = display_get_filemap (vcons->display, VM_PROT_READ); |
1147 |
|
if (*rdobj == MACH_PORT_NULL) |
1148 |
|
goto error; |
1149 |
|
break; |
1150 |
|
case O_WRITE: |
1151 |
|
*wrobj = display_get_filemap (vcons->display, VM_PROT_WRITE); |
1152 |
|
if (*wrobj == MACH_PORT_NULL) |
1153 |
|
goto error; |
1154 |
|
break; |
1155 |
|
} |
1156 |
|
mutex_unlock (&np->lock); |
1157 |
|
|
1158 |
|
*rdtype = MACH_MSG_TYPE_MOVE_SEND; |
1159 |
|
*wrtype = MACH_MSG_TYPE_MOVE_SEND; |
1160 |
|
|
1161 |
|
return 0; |
1162 |
|
|
1163 |
|
error: |
1164 |
|
mutex_unlock (&np->lock); |
1165 |
|
return errno; |
1166 |
|
} |
1167 |
|
|
1168 |
|
|
1169 |
|
static const struct argp_option options[] = |
1170 |
|
{ |
1171 |
|
{"encoding", 'e', "NAME", 0, "Set encoding of virtual consoles to" |
1172 |
|
" NAME (default `" DEFAULT_ENCODING "')" }, |
1173 |
|
{0} |
1174 |
|
}; |
1175 |
|
|
1176 |
|
static error_t |
1177 |
|
parse_opt (int opt, char *arg, struct argp_state *state) |
1178 |
|
{ |
1179 |
|
cons_t cons = state->input; |
1180 |
|
|
1181 |
|
switch (opt) |
1182 |
|
{ |
1183 |
|
default: |
1184 |
|
return ARGP_ERR_UNKNOWN; |
1185 |
|
case ARGP_KEY_SUCCESS: |
1186 |
|
case ARGP_KEY_ERROR: |
1187 |
|
break; |
1188 |
|
|
1189 |
|
case ARGP_KEY_INIT: |
1190 |
|
mutex_lock (&cons->lock); |
1191 |
|
break; |
1192 |
|
|
1193 |
|
case ARGP_KEY_FINI: |
1194 |
|
mutex_unlock (&cons->lock); |
1195 |
|
break; |
1196 |
|
|
1197 |
|
case 'e': |
1198 |
|
/* XXX Check validity of encoding. Can we perform all necessary |
1199 |
|
conversions? */ |
1200 |
|
{ |
1201 |
|
char *new = strdup (arg); |
1202 |
|
if (!new) |
1203 |
|
return ENOMEM; |
1204 |
|
if (cons->encoding) |
1205 |
|
free (cons->encoding); |
1206 |
|
cons->encoding = new; |
1207 |
|
} |
1208 |
|
break; |
1209 |
|
} |
1210 |
|
return 0; |
1211 |
|
} |
1212 |
|
|
1213 |
|
/* Return an argz string describing the current options. Fill *ARGZ |
1214 |
|
with a pointer to newly malloced storage holding the list and *LEN |
1215 |
|
to the length of that storage. */ |
1216 |
|
error_t |
1217 |
|
netfs_append_args (char **argz, size_t *argz_len) |
1218 |
|
{ |
1219 |
|
error_t err = 0; |
1220 |
|
cons_t cons = netfs_root_node->nn->cons; |
1221 |
|
|
1222 |
|
if (cons->encoding && strcmp (cons->encoding, DEFAULT_ENCODING)) |
1223 |
|
{ |
1224 |
|
char *buf; |
1225 |
|
asprintf (&buf, "--encoding=%s", cons->encoding); |
1226 |
|
if (buf) |
1227 |
|
err = argz_add (argz, argz_len, buf); |
1228 |
|
else |
1229 |
|
err = errno; |
1230 |
|
} |
1231 |
|
return err; |
1232 |
|
} |
1233 |
|
|
1234 |
|
|
1235 |
int |
int |
1236 |
main (int argc, char **argv) |
main (int argc, char **argv) |
1237 |
{ |
{ |
1238 |
error_t err; |
error_t err; |
1239 |
mach_port_t bootstrap; |
mach_port_t bootstrap; |
1240 |
struct stat ul_stat; |
struct stat ul_stat; |
1241 |
struct netnode root_nn = { cons: cons, vcons: 0 }; |
cons_t cons; |
1242 |
|
struct netnode root_nn = { vcons: 0 }; |
1243 |
mtrace(); |
struct argp argp = { options, parse_opt, NULL, |
1244 |
struct argp argp |
"A translator that provides virtual consoles." }; |
1245 |
= { NULL, NULL, NULL, |
|
1246 |
"A translator that provides virtual console displays." }; |
cons = malloc (sizeof (struct cons)); |
1247 |
|
if (!malloc) |
1248 |
|
error (1, ENOMEM, "Cannot create console structure"); |
1249 |
|
mutex_init (&cons->lock); |
1250 |
|
cons->encoding = NULL; |
1251 |
|
cons->vcons_list = NULL; |
1252 |
|
root_nn.cons = cons; |
1253 |
|
|
1254 |
/* Parse our command line arguments (all none of them). */ |
/* Parse our command line arguments (all none of them). */ |
1255 |
argp_parse (&argp, argc, argv, 0, 0, 0); |
argp_parse (&argp, argc, argv, 0, 0, cons); |
1256 |
|
|
1257 |
task_get_bootstrap_port (mach_task_self (), &bootstrap); |
task_get_bootstrap_port (mach_task_self (), &bootstrap); |
1258 |
|
|
1259 |
netfs_init (); |
netfs_init (); |
1260 |
|
|
1261 |
|
display_init (); |
1262 |
|
|
1263 |
/* Create the root node (some attributes initialized below). */ |
/* Create the root node (some attributes initialized below). */ |
1264 |
netfs_root_node = netfs_make_node (&root_nn); |
netfs_root_node = netfs_make_node (&root_nn); |
1265 |
if (! netfs_root_node) |
if (! netfs_root_node) |
1266 |
error (5, ENOMEM, "Cannot create root node"); |
error (2, ENOMEM, "Cannot create root node"); |
1267 |
|
|
1268 |
err = maptime_map (0, 0, &console_maptime); |
err = maptime_map (0, 0, &console_maptime); |
1269 |
if (err) |
if (err) |
1270 |
error (6, err, "Cannot map time"); |
error (3, err, "Cannot map time"); |
1271 |
|
|
|
mutex_init (&cons->lock); |
|
|
cons->encoding = "ISO-8859-1"; |
|
1272 |
cons->node = netfs_root_node; |
cons->node = netfs_root_node; |
1273 |
cons->underlying = netfs_startup (bootstrap, O_READ); |
cons->underlying = netfs_startup (bootstrap, O_READ); |
1274 |
if (cons->underlying == MACH_PORT_NULL) |
if (cons->underlying == MACH_PORT_NULL) |
1275 |
error (5, err, "Cannot get underlying node"); |
error (4, err, "Cannot get underlying node"); |
1276 |
|
|
1277 |
err = io_stat (cons->underlying, &ul_stat); |
err = io_stat (cons->underlying, &ul_stat); |
1278 |
if (err) |
if (err) |
1279 |
error (6, err, "Cannot stat underlying node"); |
error (5, err, "Cannot stat underlying node"); |
1280 |
|
|
1281 |
/* CONS.stat_template contains some fields that are inherited by all |
/* CONS.stat_template contains some fields that are inherited by all |
1282 |
nodes we create. */ |
nodes we create. */ |
1309 |
fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME, |
fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME, |
1310 |
console_maptime); |
console_maptime); |
1311 |
|
|
1312 |
netfs_server_loop (); /* Never returns. */ |
netfs_server_loop (); |
1313 |
|
|
1314 |
/*NOTREACHED*/ |
/*NOTREACHED*/ |
1315 |
return 0; |
return 0; |
1316 |
} |
} |