205 lines
5.6 KiB
C
205 lines
5.6 KiB
C
/* This file contains the main message loop of the HGFS file system server.
|
|
*
|
|
* The entry points into this file are:
|
|
* main main program function
|
|
*
|
|
* Created:
|
|
* April 2009 (D.C. van Moolenbroek)
|
|
*/
|
|
|
|
#include "inc.h"
|
|
|
|
#include "optset.h"
|
|
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
|
|
FORWARD _PROTOTYPE( void get_work, (endpoint_t *who_e) );
|
|
FORWARD _PROTOTYPE( void send_reply, (int err, int transid) );
|
|
|
|
PRIVATE struct optset optset_table[] = {
|
|
{ "prefix", OPT_STRING, opt.prefix, sizeof(opt.prefix) },
|
|
{ "uid", OPT_INT, &opt.uid, 10 },
|
|
{ "gid", OPT_INT, &opt.gid, 10 },
|
|
{ "fmask", OPT_INT, &opt.file_mask, 8 },
|
|
{ "dmask", OPT_INT, &opt.dir_mask, 8 },
|
|
{ "icase", OPT_BOOL, &opt.case_insens, TRUE },
|
|
{ "noicase", OPT_BOOL, &opt.case_insens, FALSE },
|
|
{ NULL }
|
|
};
|
|
|
|
/* SEF functions and variables. */
|
|
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
|
|
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
|
|
FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
|
|
|
|
/*===========================================================================*
|
|
* sef_cb_init_fresh *
|
|
*===========================================================================*/
|
|
PRIVATE int sef_cb_init_fresh(type, info)
|
|
int type;
|
|
sef_init_info_t *info;
|
|
{
|
|
/* Initialize this file server. Called at startup time.
|
|
*/
|
|
int i, r;
|
|
|
|
/* Defaults */
|
|
opt.prefix[0] = 0;
|
|
opt.uid = 0;
|
|
opt.gid = 0;
|
|
opt.file_mask = 0755;
|
|
opt.dir_mask = 0755;
|
|
opt.case_insens = FALSE;
|
|
|
|
/* If we have been given an options string, parse options from there. */
|
|
for (i = 1; i < env_argc - 1; i++)
|
|
if (!strcmp(env_argv[i], "-o"))
|
|
optset_parse(optset_table, env_argv[++i]);
|
|
|
|
/* Make sure that the given path prefix doesn't end with a slash. */
|
|
for (i = strlen(opt.prefix); i > 0 && opt.prefix[i - 1] == '/'; i--);
|
|
opt.prefix[i] = 0;
|
|
|
|
/* Initialize the HGFS library. If this fails, exit immediately. */
|
|
r = hgfs_init();
|
|
if (r != OK && r != EAGAIN) {
|
|
printf("HGFS: unable to initialize HGFS library (%d)\n", r);
|
|
|
|
return r;
|
|
}
|
|
|
|
state.mounted = FALSE;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* sef_cb_signal_handler *
|
|
*===========================================================================*/
|
|
PRIVATE void sef_cb_signal_handler(int signo)
|
|
{
|
|
/* Only check for termination signal, ignore anything else. */
|
|
if (signo != SIGTERM) return;
|
|
|
|
if (state.mounted) {
|
|
dprintf(("HGFS: got SIGTERM, still mounted\n"));
|
|
}
|
|
else {
|
|
dprintf(("HGFS: got SIGTERM, shutting down\n"));
|
|
|
|
/* Pass on the cleanup request to the HGFS library. */
|
|
hgfs_cleanup();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* sef_local_startup *
|
|
*===========================================================================*/
|
|
PRIVATE void sef_local_startup()
|
|
{
|
|
/* Register init callbacks. */
|
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
|
sef_setcb_init_restart(sef_cb_init_fresh);
|
|
|
|
/* No live update support yet. */
|
|
|
|
/* Register signal callbacks. */
|
|
sef_setcb_signal_handler(sef_cb_signal_handler);
|
|
|
|
sef_startup();
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* main *
|
|
*===========================================================================*/
|
|
PUBLIC int main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
/* The main function of this file server. After initializing, loop forever
|
|
* receiving one request from VFS at a time, processing it, and sending a
|
|
* reply back to VFS.
|
|
*/
|
|
endpoint_t who_e;
|
|
int call_nr, err, transid;
|
|
|
|
env_setargs(argc, argv);
|
|
sef_local_startup();
|
|
|
|
for (;;) {
|
|
get_work(&who_e);
|
|
|
|
transid = TRNS_GET_ID(m_in.m_type);
|
|
m_in.m_type = TRNS_DEL_ID(m_in.m_type);
|
|
if (m_in.m_type == 0) {
|
|
assert(!IS_VFS_FS_TRANSID(transid));
|
|
m_in.m_type = transid; /* Backwards compat. */
|
|
transid = 0;
|
|
} else
|
|
assert(IS_VFS_FS_TRANSID(transid));
|
|
|
|
call_nr = m_in.m_type;
|
|
if (who_e != VFS_PROC_NR) {
|
|
continue;
|
|
}
|
|
|
|
if (state.mounted || call_nr == REQ_READSUPER) {
|
|
call_nr -= VFS_BASE;
|
|
|
|
dprintf(("HGFS: call %d\n", call_nr));
|
|
|
|
if (call_nr >= 0 && call_nr < NREQS) {
|
|
err = (*call_vec[call_nr])();
|
|
} else {
|
|
err = ENOSYS;
|
|
}
|
|
|
|
dprintf(("HGFS: call %d result %d\n", call_nr, err));
|
|
}
|
|
else err = EINVAL;
|
|
|
|
send_reply(err, transid);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* get_work *
|
|
*===========================================================================*/
|
|
PRIVATE void get_work(who_e)
|
|
endpoint_t *who_e;
|
|
{
|
|
/* Receive a request message from VFS. Return the request call number.
|
|
*/
|
|
int r;
|
|
|
|
if ((r = sef_receive(ANY, &m_in)) != OK)
|
|
panic("receive failed: %d", r);
|
|
|
|
*who_e = m_in.m_source;
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* send_reply *
|
|
*===========================================================================*/
|
|
PRIVATE void send_reply(err, transid)
|
|
int err; /* resulting error code */
|
|
int transid;
|
|
{
|
|
/* Send a reply message to the requesting party, with the given error code.
|
|
*/
|
|
int r;
|
|
|
|
m_out.m_type = err;
|
|
if (IS_VFS_FS_TRANSID(transid)) {
|
|
/* If a transaction ID was set, reset it */
|
|
m_out.m_type = TRNS_ADD_ID(m_out.m_type, transid);
|
|
}
|
|
if ((r = send(m_in.m_source, &m_out)) != OK)
|
|
printf("HGFS: send failed (%d)\n", r);
|
|
}
|
|
|