common.c revision 1878
961N/A/*
961N/A* CDDL HEADER START
961N/A*
961N/A* The contents of this file are subject to the terms of the
961N/A* Common Development and Distribution License, Version 1.0 only
961N/A* (the "License"). You may not use this file except in compliance
961N/A* with the License.
961N/A*
961N/A* You can obtain a copy of the license at
961N/A* trunk/opends/resource/legal-notices/OpenDS.LICENSE
961N/A* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
961N/A* See the License for the specific language governing permissions
961N/A* and limitations under the License.
961N/A*
961N/A* When distributing Covered Code, include this CDDL HEADER in each
961N/A* file and include the License file at
961N/A* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
961N/A* add the following below this CDDL HEADER, with the fields enclosed
961N/A* by brackets "[]" replaced with your own identifying * information:
961N/A* Portions Copyright [yyyy] [name of copyright owner]
961N/A*
961N/A* CDDL HEADER END
961N/A*
961N/A*
961N/A* Portions Copyright 2007 Sun Microsystems, Inc.
961N/A*/
961N/A
961N/A#include "common.h"
1298N/A#include <errno.h>
1298N/A#include <fcntl.h>
1298N/A#include <io.h>
1298N/A#include <stdio.h>
1298N/A#include <sys/locking.h>
1298N/A#include <time.h>
1298N/A
1298N/ABOOL DEBUG = TRUE;
1298N/Achar * DEBUG_LOG_NAME = "native-windows.out";
1298N/ADWORD MAX_DEBUG_LOG_SIZE = 500 * 1000;
1298N/Achar * getDebugLogFileName();
1298N/Avoid debugInner(BOOL isError, const char *msg, va_list ap);
1298N/Avoid deleteIfLargerThan(char * fileName, DWORD maxSize);
961N/A
961N/A// ----------------------------------------------------
961N/A// Function used to create a process with the given command.
961N/A// The information about the process is stored in procInfo.
961N/A// The function returns TRUE if the process could be created
961N/A// and FALSE otherwise.
961N/A// ----------------------------------------------------
961N/ABOOL createChildProcess(char* command, BOOL background,
961N/APROCESS_INFORMATION* procInfo)
961N/A{
961N/A BOOL createOk;
961N/A STARTUPINFO startInfo; // info to pass to the new process
961N/A DWORD processFlag; // background process flag
961N/A
1878N/A debug("Attempting to create child process '%s' background=%d.", command,
1878N/A background);
1298N/A
961N/A // reset process info first
961N/A ZeroMemory(procInfo, sizeof(PROCESS_INFORMATION));
961N/A
961N/A // initialize handles to pass to the child process
961N/A ZeroMemory(&startInfo, sizeof(STARTUPINFO));
961N/A startInfo.cb = sizeof(STARTUPINFO);
961N/A startInfo.dwFlags |= STARTF_USESTDHANDLES; // use handles above
961N/A
961N/A // Create the child process
961N/A processFlag = background == TRUE ? DETACHED_PROCESS : 0;
961N/A createOk = CreateProcess(
1298N/A NULL, // application name
1298N/A command, // command line
1298N/A NULL, // process security attributes
1298N/A NULL, // primary thread security attributes
1298N/A TRUE, // handles are inherited
1298N/A processFlag, // creation flags
1298N/A NULL, // use parent's environment
1298N/A NULL, // use parent's current directory
1298N/A &startInfo, // STARTUPINFO pointer
1298N/A procInfo // receives PROCESS_INFORMATION
961N/A );
961N/A
1298N/A if (createOk)
1298N/A {
1298N/A debug("Successfully created child process '%s'.", command);
1298N/A }
1298N/A else
1298N/A {
1878N/A debugError("Failed to create child process '%s'. Last error = %d.",
1878N/A command, GetLastError());
1298N/A }
1298N/A
961N/A return createOk;
961N/A} // createChildProcess
961N/A
961N/A// ----------------------------------------------------
961N/A// Function used to launch a process for the given command
961N/A// If the process could be created it returns the pid of
961N/A// the created process and -1 otherwise.
961N/A// ----------------------------------------------------
961N/Aint spawn(const char* command, BOOL background)
961N/A{
1298N/A DWORD childPid = -1; // child's pid
961N/A PROCESS_INFORMATION procInfo; // info on the new process
961N/A BOOL createOk;
961N/A
961N/A createOk = createChildProcess((char*)command, background, &procInfo);
961N/A
961N/A if(createOk)
961N/A {
961N/A childPid = procInfo.dwProcessId;
961N/A }
961N/A
961N/A if (childPid != -1)
961N/A {
1298N/A debug("The PID of the spawned process is %d.", childPid);
961N/A return childPid;
961N/A }
961N/A else
961N/A {
1298N/A debugError("Could not get the PID of the spawned process.");
961N/A return -1;
961N/A }
961N/A} // spawn
961N/A
1298N/A
1298N/A// ---------------------------------------------------
1298N/A// Debug utility.
1298N/A// ---------------------------------------------------
1298N/Avoid debug(const char *msg, ...)
1298N/A{
1298N/A va_list ap;
1298N/A va_start (ap, msg);
1298N/A debugInner(FALSE, msg, ap);
1298N/A va_end (ap);
1298N/A}
1298N/A
1298N/Avoid debugError(const char *msg, ...)
1298N/A{
1298N/A va_list ap;
1298N/A va_start (ap, msg);
1298N/A debugInner(TRUE, msg, ap);
1298N/A va_end (ap);
1298N/A}
1298N/A
1298N/Avoid debugInner(BOOL isError, const char *msg, va_list ap)
1298N/A{
1298N/A static DWORD currentProcessPid = 0;
1298N/A static BOOL noMessageLogged = TRUE;
1298N/A
1298N/A // The file containing the log.
1298N/A char * logFile;
1298N/A FILE *fp;
1298N/A time_t rawtime;
1298N/A struct tm * timeinfo;
1298N/A char formattedTime[100];
1298N/A
1298N/A if (noMessageLogged)
1298N/A {
1298N/A currentProcessPid = GetCurrentProcessId();
1298N/A noMessageLogged = FALSE;
1878N/A debug("--------------- FIRST LOG MESSAGE FROM '%s' ---------------",
1878N/A _pgmptr);
1298N/A }
1298N/A
1298N/A // Time-stamp
1298N/A time(&rawtime);
1298N/A timeinfo = localtime(&rawtime);
1298N/A strftime(formattedTime, 100, "%Y/%m/%d %H:%M:%S", timeinfo);
1298N/A
1298N/A logFile = getDebugLogFileName();
1298N/A deleteIfLargerThan(logFile, MAX_DEBUG_LOG_SIZE);
1298N/A if ((fp = fopen(logFile, "a")) != NULL)
1298N/A {
1298N/A fprintf(fp, "%s: (pid=%d) ", formattedTime, currentProcessPid);
1298N/A if (isError)
1298N/A {
1298N/A fprintf(fp, "ERROR: ");
1298N/A // It would be nice to echo to stderr, but that doesn't appear to work.
1298N/A }
1298N/A
1298N/A vfprintf(fp, msg, ap);
1298N/A
1298N/A fprintf(fp, "\n");
1298N/A fclose(fp);
1298N/A }
1298N/A else
1298N/A {
1298N/A fprintf(stdout, "Could not create log file.\n");
1298N/A }
1298N/A}
1298N/A
1298N/A// ---------------------------------------------------------------
1298N/A// Get the fully-qualified debug log file name. The logic in this
1298N/A// method assumes that the executable of this process is in a
1298N/A// direct subdirectory of the instance root.
1298N/A// ---------------------------------------------------------------
1298N/A
1298N/Achar * getDebugLogFileName()
1298N/A{
1298N/A static char * logFile = NULL;
1298N/A char path [MAX_PATH];
1298N/A char execName [MAX_PATH];
1298N/A char * lastSlash;
1298N/A
1298N/A if (logFile != NULL)
1298N/A {
1298N/A return logFile;
1298N/A }
1298N/A
1298N/A // Get the name of the executable.
1298N/A GetModuleFileName (
1298N/A NULL,
1298N/A execName,
1298N/A MAX_PATH
1298N/A );
1298N/A
1878N/A // Cut everything after the last slash, twice. This will take us back to the
1878N/A // instance root.
1298N/A // This logic assumes that we are in a directory above the instance root.
1298N/A lastSlash = strrchr(execName, '\\');
1298N/A lastSlash[0] = '\0';
1298N/A lastSlash = strrchr(execName, '\\');
1298N/A lastSlash[0] = '\0';
1298N/A
1298N/A sprintf(path, "%s\\logs\\%s", execName, DEBUG_LOG_NAME);
1298N/A logFile = _strdup(path);
1298N/A
1298N/A return logFile;
1298N/A}
1298N/A
1298N/A// ---------------------------------------------------------------
1298N/A// Function called to know if the --debug option was passed
1298N/A// when calling this executable or not. The DEBUG variable is
1298N/A// updated accordingly.
1298N/A// ---------------------------------------------------------------
1298N/A
1298N/Avoid updateDebugFlag(char* argv[], int argc)
1298N/A{
1298N/A int i;
1298N/A DEBUG = FALSE;
1298N/A for (i=1; (i<argc) && !DEBUG; i++)
1298N/A {
1298N/A if (strcmp(argv[i], "--debug") == 0)
1298N/A {
1298N/A DEBUG = TRUE;
1298N/A }
1298N/A }
1298N/A}
1298N/A
1298N/A// ---------------------------------------------------------------
1298N/A// Deletes a file if it's larger than the given maximum size.
1298N/A// ---------------------------------------------------------------
1298N/A
1298N/Avoid deleteIfLargerThan(char * fileName, DWORD maxSize)
1298N/A{
1298N/A DWORD fileSize = 0;
1298N/A HANDLE fileHandle = CreateFile(
1298N/A fileName,
1298N/A 0,
1298N/A FILE_SHARE_READ | FILE_SHARE_WRITE,
1298N/A NULL,
1298N/A OPEN_EXISTING,
1298N/A 0,
1298N/A NULL
1298N/A );
1298N/A
1298N/A if (fileHandle == INVALID_HANDLE_VALUE)
1298N/A {
1298N/A return;
1298N/A }
1298N/A
1298N/A fileSize = GetFileSize(fileHandle, NULL);
1298N/A
1298N/A CloseHandle(fileHandle);
1298N/A
1298N/A if (fileSize > maxSize)
1298N/A {
1298N/A DeleteFile(fileName);
1298N/A }
1298N/A}