int
wisvc_Handle_W_option (int argc, char **argv,
		       char *s, int *i_ptr, int called_as_service)
{
  char *work_dir = (s + 2);

  if (!*work_dir)		/* directory in the next arg? */
    {
      if ((++(*i_ptr) >= argc) || !(work_dir = argv[(*i_ptr)]))
	{
	  err_printf ((
			"%s: Directory name missing after command line option \"%s\", exiting.\n",
			argv[0], s));
	  kubl_main_exit (1);
	}
    }

  if (chdir (work_dir))		/* Is not zero, i.e. -1, an error. */
    {
/*   setWindowsError(); */
      err_printf (("%s: Cannot chdir to \"%s\" because: %s",
		   argv[0], work_dir, strerror (errno)));
      kubl_main_exit (1);
    }

  return (0);			/* Return 0 to indicate that everything went all right. */
}
int
wisvc_Handle_I_and_J_options (int argc, char **argv,
			      char *s, int i, int autostart)
{
  int called_as_service = 0;
  size_t path_len;
  int start_now = 0;
  char *service_name = (*(s + 2) ? (s + 2) : WISVC_DEFAULT_SERVICE_NAME);
  char *progname = argv[0];
  char *last_of_path, *cutpnt;
  char BinaryPathName[(MAX_BINARY_PATH) + 10];

/*
   if(i > 1)
   {
   err_printf((
   "%s: If you give %s option, it MUST be the first argument on command line!",
   progname,s));
   kubl_main_exit(1);
   }
 */

/* Then construct absolute path to this binary executable
   by combining working directory path got with getcwd
   with the program name got from argv[0].
   Note that the program name itself can be relative or absolute path.
   getcwd returns a string that represents the path of
   the current working directory. If the current working
   directory is the root, the string ends with a backslash (\).
   If the current working directory is a directory
   other than the root, the string ends with the directory
   name and not with a backslash.
   Note that absolute paths with upward parts (..)
   like the one below seem to work equally well, so
   we do not need to worry about .. :s and .:s in any
   special way.
   D:\inetpub\wwwroot\..\..\ic\.\diskit\wi\windebug\wi.exe
 */

  if (is_abs_path (progname))
    {
      strncpy (BinaryPathName, progname, (MAX_BINARY_PATH));
    }
  else
    /* We have to combine pwd + relative starting path */
    {
      if (NULL == getcwd (BinaryPathName, _MAX_PATH))
	{
	  err_printf (("%s: Cannot getcwd because: %s",
		       progname, strerror (errno)));
	  exit (1);
	}
      path_len = strlen (BinaryPathName);
      last_of_path = (BinaryPathName + path_len - 1);
      if ((0 == path_len) || !is_abs_path (last_of_path))
	{			/* Add the missing path separator between if needed */
	  strncat_ck (BinaryPathName, "\\", (MAX_BINARY_PATH));
	}
      /* And then the progname itself. */
      strncat_ck (BinaryPathName, progname, (MAX_BINARY_PATH));
    }

  /* Add our own special .eXe extension to the program name, so that
     when service is started, the code in main can see from argv[0]
     that it was started as a service, not as an ordinary command
     line program.
   */
  strncat_ck (BinaryPathName, WISVC_EXE_EXTENSION_FOR_SERVICE, (MAX_BINARY_PATH));

  /* Do chdir to the same directory where the executable is, needed
     because of wi.cfg check soon performed. */
  if ((NULL != (cutpnt = strrchr (BinaryPathName, '\\'))))
    {				/* Search the last backslash. */
      unsigned char
        save_the_following_char = *(((unsigned char *) cutpnt) + 1);
      *(cutpnt + 1) = '\0';

      if (chdir (BinaryPathName))	/* Is not zero, i.e. -1, an error. */
	{			/* However, we do not exit yet. */
	  err_printf (("%s: Cannot chdir to \"%s\" because: %s",
		       argv[0], BinaryPathName, strerror (errno)));
	  exit (1);
	}

      *(((unsigned char *) cutpnt) + 1) = save_the_following_char;
    }


/* Add all command line arguments after the absolute program name
   itself, separated by spaces. The started service will see them
   in the elements of argv vector, in the normal way, that is
   argv[0] will contain just the absolute program name which ends with
   .eXe and arguments are in argv[1], argv[2], etc.

   Check also for options -S (start the service), and -W change working
   directory. The latter would not be actually necessary to do here,
   but, if the directory is invalid, then it is much more friendly
   to give an error message here, than let the service itself fail,
   and hide the same error message to god knows which log file.
   Check that the user does not try to give options -D, -U, -R or -d
   to the service to be installed.

 */

  for (i = 1; i < argc; i++)
    {
      s = argv[i];
      if ('-' == s[0])
	{
	  switch (s[1])
	    {			/* With -S ignore the possibility that a different service
				   name could be specified after it than after -I or -J
				   DON'T ADD OPTIONS -S, -I or -J to BinaryPathName, as
				   they would be ignored anyway in service. */
	    case 'S':
	      {
		start_now = 1;
		continue;
	      }
	    case 'I':
	    case 'J':
	      {
		continue;
	      }
	    case 'W':
	      {
		int stat
		= wisvc_Handle_W_option (argc, argv, s, &i, called_as_service);
		if (stat)
		  {
		    kubl_main_exit (stat);
		  }
		break;
	      }
	    case 'D':
	    case 'U':		/* case 'R': */
	    case 'd':
	      {
		err_printf ((
			      "%s: Sorry, the option %s can be used only from command line, not in service!\n",
			      argv[0], s));
		exit (1);
	      }
	    }
	}

      strncat_ck (BinaryPathName, " ", (MAX_BINARY_PATH));
      strncat_ck (BinaryPathName, argv[i], (MAX_BINARY_PATH));
    }

  {				/* Check already HERE that there is a config file in the final
				   working directory, for the same user-friendly reason as
				   checking the validity of -W option's argument. */
    int fd = open (CFG_FILE, O_RDWR);
    if (fd < 0)
      {
	err_printf ((
		      "There must be a %s file in the server's working directory. Exiting.\n",
		      CFG_FILE));
	exit (-1);
      }
    fd_close (fd, NULL);	/* Defined in widisk.h */
  }

  wisvc_CreateKublService (argc, argv, service_name, BinaryPathName,
			   autostart, start_now);

  return (0);
}
Exemple #3
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;
}