155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* This file contains the SFFS initialization code and message loop.
 | |
|  *
 | |
|  * The entry points into this file are:
 | |
|  *   sffs_init		initialization
 | |
|  *   sffs_signal	signal handler
 | |
|  *   sffs_loop		main message loop
 | |
|  *
 | |
|  * Created:
 | |
|  *   April 2009 (D.C. van Moolenbroek)
 | |
|  */
 | |
| 
 | |
| #include "inc.h"
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				sffs_init				     *
 | |
|  *===========================================================================*/
 | |
| int sffs_init(char *name, const struct sffs_table *table,
 | |
|   struct sffs_params *params)
 | |
| {
 | |
| /* Initialize this file server. Called at startup time.
 | |
|  */
 | |
|   int i;
 | |
| 
 | |
|   /* Make sure that the given path prefix doesn't end with a slash. */
 | |
|   i = strlen(params->p_prefix);
 | |
|   while (i > 0 && params->p_prefix[i - 1] == '/') i--;
 | |
|   params->p_prefix[i] = 0;
 | |
| 
 | |
|   state.s_mounted = FALSE;
 | |
|   state.s_signaled = FALSE;
 | |
| 
 | |
|   sffs_name = name;
 | |
|   sffs_table = table;
 | |
|   sffs_params = params;
 | |
| 
 | |
|   return OK;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				sffs_signal				     *
 | |
|  *===========================================================================*/
 | |
| void sffs_signal(int signo)
 | |
| {
 | |
| 
 | |
|   /* Only check for termination signal, ignore anything else. */
 | |
|   if (signo != SIGTERM) return;
 | |
| 
 | |
|   /* We can now terminate if we have also been unmounted. */
 | |
|   state.s_signaled = TRUE;
 | |
| 
 | |
|   if (state.s_mounted) {
 | |
| 	dprintf(("%s: got SIGTERM, still mounted\n", sffs_name));
 | |
|   } else {
 | |
| 	dprintf(("%s: got SIGTERM, shutting down\n", sffs_name));
 | |
| 
 | |
| 	/* Break out of the main loop, giving the main program the chance to
 | |
| 	 * perform further cleanup. This causes sef_receive() to return with
 | |
| 	 * an EINTR error code.
 | |
| 	 */
 | |
| 	sef_cancel();
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				get_work				     *
 | |
|  *===========================================================================*/
 | |
| static int get_work(endpoint_t *who_e)
 | |
| {
 | |
| /* Receive a request message from VFS. Return TRUE if a new message is ready
 | |
|  * to be processed, or FALSE if sef_stop() was called from the signal handler.
 | |
|  */
 | |
|   int r;
 | |
| 
 | |
|   if ((r = sef_receive(ANY, &m_in)) != OK) {
 | |
| 	if (r != EINTR)
 | |
| 		panic("receive failed: %d", r);
 | |
| 
 | |
| 	return FALSE;
 | |
|   }
 | |
| 
 | |
|   *who_e = m_in.m_source;
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				send_reply				     *
 | |
|  *===========================================================================*/
 | |
| static void send_reply(
 | |
| 	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 = ipc_send(m_in.m_source, &m_out)) != OK)
 | |
| 	printf("%s: ipc_send failed (%d)\n", sffs_name, r);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				sffs_loop				     *
 | |
|  *===========================================================================*/
 | |
| void sffs_loop(void)
 | |
| {
 | |
| /* The main function of this file server. After initializing, loop, receiving
 | |
|  * one request from VFS at a time, processing it, and sending a reply back to
 | |
|  * VFS. Termination occurs when we both have been unmounted and have received
 | |
|  * a termination signal.
 | |
|  */
 | |
|   endpoint_t who_e;
 | |
|   int call_nr, err, transid;
 | |
| 
 | |
|   while (state.s_mounted || !state.s_signaled) {
 | |
| 	if (!get_work(&who_e))
 | |
| 		continue;	/* Recheck running conditions */
 | |
| 
 | |
| 	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.s_mounted || call_nr == REQ_READSUPER) {
 | |
| 		call_nr -= FS_BASE;
 | |
| 
 | |
| 		dprintf(("%s: call %d\n", sffs_name, call_nr));
 | |
| 
 | |
| 		if (call_nr >= 0 && call_nr < NREQS) {
 | |
| 			err = (*call_vec[call_nr])();
 | |
| 		} else {
 | |
| 			err = ENOSYS;
 | |
| 		}
 | |
| 
 | |
| 		dprintf(("%s: call %d result %d\n", sffs_name, call_nr, err));
 | |
| 	}
 | |
| 	else err = EINVAL;
 | |
| 
 | |
| 	send_reply(err, transid);
 | |
|   }
 | |
| }
 | 
