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); }
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; }