Ejemplo n.º 1
0
int
kubl_main (int argc, char **argv, int called_as_service, DWORD * errptr)
{
  int i, exit_after_options = 0, started_with_itself = 0;
  int read_from_rebuilt_database = 0;	/* For -R option. */
  int dump_for_recovery = 0;	/* For -D option. */
  char *empty = "";
  char *mode = empty;
  char *addr = KUBL_DEFAULT_PORT;
  char *service_name = (called_as_service ? argv[0] : NULL);
  char *s;

#ifdef PMN_LOG
  log_open_fp (stderr, LOG_DEBUG, L_MASK_ALL, L_STYLE_GROUP|L_STYLE_TIME);

  log_open_file ("wi.err", LOG_DEBUG, L_MASK_ALL, L_STYLE_GROUP | L_STYLE_TIME);
#endif

  /* If not overridden with any arguments specified with StartService,
     (i.e. either there are no args at all, or there is just -S)
     then use the permanent arguments (saved into wisvc_Main_G_argv)
     got from the original BinaryPath constructed in
     wisvc_Handle_I_and_J_options
   */
  if (called_as_service &&
      (((argc == 2) && !strncmp (argv[1], "-S", 2)) || (argc < 2))
    )
    {
      if (argc == 2)
	{
	  started_with_itself = 1;
	}
      argc = wisvc_Main_G_argc;
      argv = wisvc_Main_G_argv;
    }

  /* For debugging
     log_error (
     "kubl_main called with argc=%d, argv[0]=%s, argv[1]=%s, called_as_service=%d pid=%d",
     argc, argv[0], ((argc > 1) ? argv[1] : "NULL"),
     called_as_service, getpid());
   */

  /* If coming from KublServiceStart then argv vector seems to be NOT
     terminated by NULL (contrary to what MS documentation claims),
     so let's check that i stays smaller than argc. */
  for (i = 1; i < argc; i++)
    {
      s = argv[i];
      if ('-' == *s)
	{
	  if (mode == empty)
	    {
	      mode = s;
	    }
	  switch (*(s + 1))
	    {
#ifdef WIN32
	    case 'I':
	    case 'J':		/* Install to services. I =with autostart */
	      {
		int stat;
		if (mode == s)
		  {
		    mode = empty;
		  }
		if (called_as_service)
		  {
		    break;
		  }		/* Ignore in service. */
		stat = wisvc_Handle_I_and_J_options (argc, argv, s, i,
						     ('I' == *(s + 1)));
		kubl_main_exit (stat);
	      }
	    case 'S':		/* Start a previously installed service. */
	      {			/* Might be on the same command line as -J (or -I) */
		/* in which case Handle_I_and_J_options has the
		   responsibility to start it, directly from
		   CreateKublServices */
		int j, stat;
		char *service_name =
		(*(s + 2) ? (s + 2) : WISVC_DEFAULT_SERVICE_NAME);
		SC_HANDLE schandle;

		if (mode == s)
		  {
		    mode = empty;
		  }
		if (called_as_service)
		  {
		    started_with_itself = 1;
		    break;
		  }		/* Ignore in service. */

		/* We COULD copy the rest of argv vector one left, squashing -S
		   itself out of the existence, but we DON'T do it, as
		   -S option is an important signal to the started server
		   that it was started with wi.exe itself, not by clicking
		   the start button in services icon of Control Panel.
		   The difference is that with the latter starting way
		   the service is reported to be successfully started almost
		   immediately (before the initializations and log roll forward)
		   while the wi -S way of starting ensures that after the wi -S
		   command exits we know that the service is really started
		   all the way up and listening. This feature is needed in few
		   test scripts that turn Kubl server on and off, on and off. */
		/* for(j=i; j < argc; j++) { argv[j] = argv[j+1]; } argc--; */

		schandle = wisvc_OpenKublService (argv, service_name, "start",
					  (GENERIC_EXECUTE | GENERIC_READ));

		/* Returns 1 if started for sure, 0 if failed or unsure. */
		stat = wisvc_StartKublService (argc, argv, schandle,
					       service_name, argv[0], 0);

		/* Returns exit status 0 (= success) if certainly started, */
		kubl_main_exit (!stat);		/* otherwise 1 (= failure). */
		break;
	      }
	    case 'U':		/* Uninstall from Services. */
	      {
		char *service_name =
		(*(s + 2) ? (s + 2) : WISVC_DEFAULT_SERVICE_NAME);

		if (mode == s)
		  {
		    mode = empty;
		  }

		wisvc_UninstallKublService (argv, service_name);

		exit_after_options = 1;
		break;
	      }
#endif
	    case 'd':
#ifdef DBG_BLOB_PAGES_ACCOUNT
	      f_backup_dump = 1;
#endif
	      is_db_to_log = 1;
	      break;
	    case 'D':
	      {
		dump_for_recovery = (i + 1);
		goto out;
	      }
	    case 'R':
	      {
		read_from_rebuilt_database = 1;
		f_read_from_rebuilt_database = 1;
		break;
	      }
	    case 'j':
	      ob_just_report = 1;
	      /* fall to the next */
	    case 'r':
	      {
		if (i < argc - 1)
		  recover_file_prefix = argv[i+1];
		i++;
		break;
	      }
	    case 'B':
	      {
		if (i < argc - 1)
		  backup_dirs = argv[i+1];
		goto out;
	      }
	    case 'W':		/* Change working directory. */
	      {
		int stat;

		if (mode == s)
		  {
		    mode = empty;
		  }
		stat = wisvc_Handle_W_option (argc, argv, s, &i, called_as_service);
		if (stat)
		  {
		    kubl_main_exit (stat);
		  }
		break;
	      }
	    default:		/* E.g. everything else like -? -H or -h for help. */
	      {
		chil_usage (argv);
		kubl_main_exit (0);
	      }
	    }
	}
      else if (isdigit (*s))
	{
	  addr = s;
	}
      else
	{
	  dbg_printf (("%s: Don't know what to do with command line argument \"%s\". Read this:\n",
	      argv[0], s));
	  chil_usage (argv);
	  kubl_main_exit (1);
	}
    }				/* For loop over arguments. */
out:;

  if (exit_after_options)
    {
      kubl_main_exit (0);
    }

  /* If called as service and this was not started with wi -S
     (The -S option was not present in command line arguments)
     then this presumably is started with a start button from
     services manager of Control Panel. In that case, send
     SERVICE_RUNNING status immediately, so that it won't start waiting
     for memory initializations and log roll forwards, as its patience
     would not be enough for it, and it would instead falsely claim
     that:
     "Could not start the Kubl service on \\ARTAUD. Error 2186:
     The service is not responding to the control function."
   */

  if (called_as_service && !started_with_itself)
    {
      wisvc_send_service_running_status ();
    }

#ifndef WIN32
  signal (SIGPIPE, SIG_IGN);
#endif
  srv_global_init (mode);

  if (recover_file_prefix)
    {
      kubl_main_exit (0);
    }

  if (read_from_rebuilt_database)
    {
      kubl_main_exit (0);
    }


  if (is_db_to_log)
    {
      db_to_log ();
      kubl_main_exit (0);
    }

  /* If there was -D option, then dump_for_recovery is set to
     an index of argv one right to it, where might be one or more
     recovery keys. */
  if (dump_for_recovery)
    {
      for (i = dump_for_recovery; i < argc; i++)
	{
	  int k = atoi (argv[i]);
	  if (k)
	    db_recover_key (k, k);
	}
      db_crash_to_log (mode);
      kubl_main_exit (0);
    }

  tcpses_set_reuse_address (1);
  listening = PrpcListen (addr, SESCLASS_TCPIP);
  server_port = tcpses_get_port (listening->dks_session);
  if (!DKSESSTAT_ISSET (listening, SST_LISTENING))
    {
      kubl_main_exit (1);
    }
  if (service_name)		/* Started as a Windows NT service? */
    {
      log_info ("Server started at %s as service %s, pid=%d",
	  addr, service_name, getpid ());
    }
  else
    {
      log_info ("Server started at %s, pid=%d", addr, getpid ());
    }
  virtuoso_server_initialized = 1;


  if (!strchr (mode, 'b'))
    http_init_part_two ();
#ifdef REPLICATION
  if (read_from_rebuilt_database)	/* if booting from crash log, */
    {				/* go read the account levels from db */
      repl_read_db_levels ();
    }

  repl_sync_server (NULL, NULL);
#endif

  /* If called as Windows NT service, return now back to
     wisvc_KublServiceStart which in turn will call main_the_rest
     after it has set */
  if (called_as_service)
    {
      return (0);
    }				/* 0 = NO_ERROR */

#ifndef WIN32
  signal (SIGINT, sig_catcher);
  signal (SIGTERM, sig_catcher);
  signal (SIGHUP, sig_catcher);
  signal (SIGQUIT, sig_catcher);
#endif

  main_the_rest ();
  return 0;
}
Ejemplo n.º 2
0
/*
   service_read ()

   Used to read from a session. Handles scheduling
   if the session would block.

   Used for reading from a service thread. If the read would block,
   put the thread to wait. When the scheduling cycle sees input on this
   session the random_input_ready_action is called.
   This wakes up this thread and schedules it for execution on the next
   round

   The need_all argument controls whether this function may return after reading
   fewer than the requested number of bytes. This function always reads at
   least 1 byte.

   If the calling thread is the scheduling thread and io would block, this
   allows schedule and recursively blocks on all pending i/o.
   If the calling thread is some other thread, this disables
   the thread and tells the scheduler to resume this when the input is ready.

   Returns the number of bytes read.
 */
int
service_read (dk_session_t * ses, char *buffer, int req_bytes, int need_all)
{
  USE_GLOBAL
  int last_read = 0;
  int bytes = req_bytes;
  du_thread_t *cur_proc;	/* mty NEW */
  int rc;

  DBG_CHECK_READ_FAIL (ses);

  while (bytes > 0)
    {
      without_scheduling_tic ();
      if (!ses->dks_is_read_select_ready && ses->dks_session && ses->dks_session->ses_class != SESCLASS_STRING)
	{
	  tcpses_is_read_ready (ses->dks_session, &ses->dks_read_block_timeout);
	  if (DKSESSTAT_ISSET (ses, SST_TIMED_OUT))
	    rc = -1;
	  else
	    rc = session_read (ses->dks_session, &(buffer[last_read]), bytes);
	}
      else
	{
	  if (!ses->dks_session)
	    longjmp_splice (&(SESSION_SCH_DATA (ses)->sio_read_broken_context), 1);

	  rc = session_read (ses->dks_session, &(buffer[last_read]), bytes);
	}
      ses->dks_is_read_select_ready = 0;
      restore_scheduling_tic ();

      if (rc == 0)
	PROCESS_ALLOW_SCHEDULE ();
      else if (rc > 0)
	{
	  bytes = bytes - rc;
	  last_read = last_read + rc;
	  if (!need_all)
	    {
	      ses->dks_bytes_received += last_read;
	      return (last_read);
	    }
	}
      if (rc <= 0)
	{
	  if (SESSTAT_ISSET (ses->dks_session, SST_INTERRUPTED))
	    {
	      PROCESS_ALLOW_SCHEDULE ();
	    }
	  else if (SESSTAT_ISSET (ses->dks_session, SST_BLOCK_ON_READ))
	    {
	      /* would block. suspend thread */

	      cur_proc = current_process;	 /* mty NEW */
	      if (!PROCESS_TO_DK_THREAD (cur_proc))
		{
		  /* We have a block on a server thread. We recognize it
		   * because a server thread is not associated to a request.
		   * The read would block the server thread. Run others and
		   * do a recursive check_inputs to resume other threads that
		   * may now be ready for i/o. Do a timeout round to unblock
		   * threads waiting on timed-out futures if the select times
		   * out. Finally retry read.
		   */
		  int rc2;
		  PROCESS_ALLOW_SCHEDULE ();
		  rc2 = check_inputs (PASS_G & atomic_timeout, 1);
		  if (rc2 == 0)
		    timeout_round (PASS_G ses);
		}
	      else
		{
		  SESSION_SCH_DATA (ses)->sio_random_read_ready_action = unfreeze_thread_read;
		  SESSION_SCH_DATA (ses)->sio_reading_thread = cur_proc;
		  add_to_served_sessions (ses);
		  semaphore_enter (cur_proc->thr_sem);
		}
	    }
	  else if (1 ||				 /* ?? */
	      SESSTAT_ISSET (ses->dks_session, SST_TIMED_OUT) || SESSTAT_ISSET (ses->dks_session, SST_BROKEN_CONNECTION))
	    {
	      SESSTAT_CLR (ses->dks_session, SST_OK);
	      SESSTAT_SET (ses->dks_session, SST_BROKEN_CONNECTION);

	      longjmp_splice (&(SESSION_SCH_DATA (ses)->sio_read_broken_context), 1);
	    }
	  else
	    {
	      ses->dks_bytes_received += last_read;

	      ss_dprintf_2 (("Unrecognized I/O error rc=%d errno=%d in service_read.", rc, errno));
	      longjmp_splice (&(SESSION_SCH_DATA (ses)->sio_read_broken_context), 1);
	    }
	}
    }
  ses->dks_bytes_received += last_read;
  return (last_read);
}