From owner-freebsd-java Thu Mar 20 1:12:29 2003 Delivered-To: freebsd-java@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 17A1F37B401 for ; Thu, 20 Mar 2003 01:12:12 -0800 (PST) Received: from guinness.syncrontech.com (guinness.syncrontech.com [62.71.8.19]) by mx1.FreeBSD.org (Postfix) with ESMTP id 6311C43F85 for ; Thu, 20 Mar 2003 01:12:10 -0800 (PST) (envelope-from ari.suutari@syncrontech.com) Received: from coffee.syncrontech.com (coffee.syncrontech.com [62.71.8.37]) by guinness.syncrontech.com (8.12.8/8.12.8) with ESMTP id h2K9BwGS098325; Thu, 20 Mar 2003 11:11:58 +0200 (EET) (envelope-from ari.suutari@syncrontech.com) From: Ari Suutari To: Brent Verner , Doug Poland Subject: Re: Specifying jdk for tomcat 4.1.18 Date: Thu, 20 Mar 2003 11:11:57 +0200 User-Agent: KMail/1.5 Cc: leafy@leafy.idv.tw, freebsd-java@FreeBSD.ORG References: <18118.63.104.35.130.1048108215.squirrel@email.polands.org> <1671.172.16.1.33.1048126904.squirrel@email.polands.org> <20030320041206.GA46244@rcfile.org> In-Reply-To: <20030320041206.GA46244@rcfile.org> MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_dXYe+h5We6YEeP6" Message-Id: <200303201111.57618.ari.suutari@syncrontech.com> X-Scanned-By: MIMEDefang 2.24 (www . roaringpenguin . com / mimedefang) Sender: owner-freebsd-java@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org --Boundary-00=_dXYe+h5We6YEeP6 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi, On Thursday 20 March 2003 06:12, Brent Verner wrote: > I have a patch to the daemonctl.c source that causes it to use > JAVA_HOME, but this approach is not ideal, as there are other > difficulties aside from which java binary to use. I have also a patched version of daemonctl.c, which uses a configuration file in /usr/local/etc, like this: (I'll attach the source to this mail, maybe it is useful to others also) tomcat4ctl.conf: APP_HOME=/usr/local/jakarta-tomcat4.0.5 JAVA_HOME=/usr/local/linux-sun-jdk1.3.1 STDOUT_LOG=/usr/local/jakarta-tomcat4.0.5/logs/stdout.log STDERR_LOG=/usr/local/jakarta-tomcat4.0.5/logs/stderr.log STOP_TIMEOUT=5 PID_FILE=/var/run/tomcat4.pid PORTVERSION=4.0.5 APP_TITLE=Jakarta Tomcat JAVA_CMD=bin/java JAR_FILE=bin/bootstrap.jar JAVA_ARGS=-Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Dc atalina.home=/usr/local/jakarta-tomcat4.0.5 JAR_ARGS=start Ari S. --Boundary-00=_dXYe+h5We6YEeP6 Content-Type: text/x-csrc; charset="iso-8859-1"; name="daemonctl.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="daemonctl.c" /* * -*- mode: Fundamental; tab-width: 4; -*- * ex:ts=4 * * Daemon control program. * * $FreeBSD: ports/www/jakarta-tomcat4/files/daemonctl.c,v 1.6 2002/05/08 22:00:04 znerd Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* The maximum size of the PID file, in bytes */ #define MAX_FILE_SIZE 32 #define MAX_ARGS 50 /* The interval in seconds between the checks to make sure the process died after a kill */ #define STOP_TIME_INTERVAL 1 #define ERR_ILLEGAL_ARGUMENT 1 #define ERR_PID_FILE_NOT_FOUND 2 #define ERR_PID_FILE_TOO_LARGE 3 #define ERR_PID_FILE_CONTAINS_ILLEGAL_CHAR 4 #define ERR_KILL_FAILED 5 #define ERR_ALREADY_RUNNING 6 #define ERR_NOT_RUNNING 7 #define ERR_CHDIR_TO_APP_HOME 8 #define ERR_ACCESS_JAR_FILE 17 #define ERR_STDOUT_LOGFILE_OPEN 9 #define ERR_STDERR_LOGFILE_OPEN 10 #define ERR_FORK_FAILED 11 #define ERR_STAT_JAVA_HOME 12 #define ERR_JAVA_HOME_NOT_DIR 13 #define ERR_STAT_JAVA_CMD 14 #define ERR_JAVA_CMD_NOT_FILE 15 #define ERR_JAVA_CMD_NOT_EXECUTABLE 16 #define ERR_CONF_FILE_OPEN 17 #define ERR_CONF_FILE_ERROR 18 #define ERR_MALLOC 19 #define ERR_TOO_MANY_ARGS 20 #define ERR_CONFIG_MISSING 21 #define private static typedef struct _confNode { char* name; char* value; struct _confNode* next; } ConfNode; private ConfNode* confList = NULL; private char* myName = "daemonctl"; private void printUsage(void); private int openPIDFile(void); private int readPID(int); private void writePID(int file, int pid); private void start(void); private void stop(void); private void restart(void); private void readConf(char*); private char* getConfStr(char*); private int getConfInt(char*); /** * Main function. This function is called when this program is executed. * * @param argc * the number of arguments plus one, so always greater than 0. * * @param argv * the arguments in an array of character pointers, where the last argument * element is followed by a NULL element. */ int main(int argc, char *argv[]) { /* Declare variables, like all other good ANSI C programs do :) */ char *argument; readConf(argv[0]); /* Parse the arguments */ if (argc < 2) { printUsage(); return 0; } setuid(geteuid()); setgid(getegid()); argument = argv[1]; if (strcmp("start", argument) == 0) { start(); } else if (strcmp("stop", argument) == 0) { stop(); } else if (strcmp("restart", argument) == 0) { restart(); } else { fprintf(stderr, "%s: Illegal argument \"%s\".\n", myName, argument); printUsage(); exit(ERR_ILLEGAL_ARGUMENT); } return 0; } /** * Prints usage information to stdout. */ void printUsage(void) { printf("Usage: %s [ start | stop | restart ]\n", myName); } /** * Attempts to open the PID file. If that file is successfully opened, then * the file handle (an int) will be returned. * * @return * the file handle. */ int openPIDFile(void) { int file; /* Attempt to open the PID file */ file = open(getConfStr("PID_FILE"), O_RDWR); if (file < 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to open %s for reading and writing: ", myName, getConfStr("PID_FILE")); perror(NULL); exit(ERR_PID_FILE_NOT_FOUND); } return file; } /** * Reads a PID from the specified file. The file is identified by a file * handle. * * @param file * the file handle. * * @return * the PID, or -1 if the file was empty. */ int readPID(int file) { char *buffer; int hadNewline = 0; unsigned int count; unsigned int i; int pid; /* Read the PID file contents */ buffer = (char *) malloc((MAX_FILE_SIZE + 1) * sizeof(char)); count = read(file, buffer, MAX_FILE_SIZE + 1); if (count > MAX_FILE_SIZE) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: The file %s contains more than %d bytes.\n", myName, getConfStr("PID_FILE"), MAX_FILE_SIZE); exit(ERR_PID_FILE_TOO_LARGE); } /* Convert the bytes to a number */ pid = 0; for (i=0; i= '0' && c <= '9') { char digit = c - '0'; pid *= 10; pid += digit; } else if (i == (count - 1) && c == '\n') { /* XXX: Ignore a newline at the end of the file */ hadNewline = 1; } else { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: The file %s contains an illegal character (%d) at position %d.\n", myName, getConfStr("PID_FILE"), c, i); exit(ERR_PID_FILE_CONTAINS_ILLEGAL_CHAR); } } printf(" [ DONE ]\n"); if (count == 0 || (count == 1 && hadNewline == 1)) { return -1; } return pid; } /** * Writes a process ID to the specified file. The file is identified by a file * handle. * * @param file * the file handle, always greater than 0. * * @param pid * the PID to store, always greater than 0. */ void writePID(int file, int pid) { char *buffer; int nbytes; /* Check preconditions */ assert(file > 0); assert(pid > 0); printf(">> Writing PID file..."); lseek(file, (off_t) 0, SEEK_SET); ftruncate(file, (off_t) 0); nbytes = asprintf(&buffer, "%d\n", pid); write(file, buffer, nbytes); printf(" [ DONE ]\n"); } /** * Checks if the specified process is running. * * @param pid * the process id, greater than 0. * * @return * 0 if the specified process is not running, a different value otherwise. */ int existsProcess(int pid) { int result; /* Check preconditions */ assert(pid > 0); /* See if the process exists */ result = kill(pid, 0); /* If the result is 0, then the process exists */ if (result == 0) { return 1; } else { return 0; } } /** * Kills the process identified by the specified ID. * * @param pid * the process id, greater than 0. */ void killProcess(int pid) { int result; unsigned int waited; unsigned int forced; unsigned int interval = STOP_TIME_INTERVAL; unsigned int timeout = getConfInt("STOP_TIMEOUT"); /* Check preconditions */ assert(pid > 0); printf(">> Terminating process %d...", pid); result = kill(pid, SIGTERM); if (result < 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to kill process %d: ", myName, pid); perror(NULL); exit(ERR_KILL_FAILED); } /* Wait until the process is actually killed */ result = existsProcess(pid); for (waited=0; result == 1 && waited < timeout; waited += interval) { printf("."); fflush(NULL); sleep(interval); result = existsProcess(pid); } /* If the process still exists, then have no mercy and kill it */ forced = 0; if (result == 1) { /* Force the process to die */ result = kill(pid, SIGKILL); if (result == 0) { forced = 1; printf(" [ DONE ]\n"); fprintf(stderr, "%s: Process %d did not terminate within %d sec. Killed.\n", myName, timeout, pid); } else if (result != ESRCH) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to kill process %d: ", myName, pid); perror(NULL); exit(ERR_KILL_FAILED); } } if (forced == 0) { printf(" [ DONE ]\n"); } } /** * Starts the daemon. */ void start(void) { int file; int pid; int result; int stdoutLogFile; int stderrLogFile; struct stat sb; char buf[512]; char* token; char* args[MAX_ARGS]; int argCount; /* Open and read the PID file */ printf(">> Reading PID file (%s)...", getConfStr("PID_FILE")); file = openPIDFile(); pid = readPID(file); printf(">> Starting %s %s...", getConfStr("APP_TITLE"), getConfStr("PORTVERSION")); if (pid != -1) { /* Check if the process actually exists */ result = existsProcess(pid); if (result == 1) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: %s %s is already running, PID is %d.\n", myName, getConfStr("APP_TITLE"), getConfStr("PORTVERSION"), pid); exit(ERR_ALREADY_RUNNING); } } /* Check if the JDK home directory is actually a directory */ result = stat(getConfStr("JAVA_HOME"), &sb); if (result != 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to stat %s: ", myName, getConfStr("JAVA_HOME")); perror(NULL); exit(ERR_STAT_JAVA_HOME); } if (!S_ISDIR(sb.st_mode)) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Java home directory %s is not a directory.\n", myName, getConfStr("JAVA_HOME")); exit(ERR_JAVA_HOME_NOT_DIR); } /* Check if the Java command is actually an executable regular file */ sprintf (buf, "%s/%s", getConfStr("JAVA_HOME"), getConfStr("JAVA_CMD")); result = stat(buf, &sb); if (result != 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to stat %s: ", myName, buf); perror(NULL); exit(ERR_STAT_JAVA_CMD); } if (!S_ISREG(sb.st_mode)) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Java command %s is not a regular file.\n", myName, buf); exit(ERR_JAVA_CMD_NOT_FILE); } result = access(buf, X_OK); if (result != 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Java command %s is not executable: ", myName, buf); perror(NULL); exit(ERR_JAVA_CMD_NOT_EXECUTABLE); } /* Change directory */ result = chdir(getConfStr("APP_HOME")); if (result < 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to access directory %s: ", myName, getConfStr("APP_HOME")); perror(NULL); exit(ERR_CHDIR_TO_APP_HOME); } /* See if the JAR file exists */ sprintf(buf, "%s/%s", getConfStr("APP_HOME"), getConfStr("JAR_FILE")); result = access(buf, R_OK); if (result < 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to access JAR file %s: ", myName, buf); perror(NULL); exit(ERR_ACCESS_JAR_FILE); } /* Open the stdout log file */ stdoutLogFile = open(getConfStr("STDOUT_LOG"), O_WRONLY); if (stdoutLogFile < 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to open %s for writing: ", myName, getConfStr("STDOUT_LOG")); perror(NULL); exit(ERR_STDOUT_LOGFILE_OPEN); } lseek(stdoutLogFile, (off_t) 0, SEEK_END); /* Open the stderr log file */ stderrLogFile = open(getConfStr("STDERR_LOG"), O_WRONLY); if (stderrLogFile < 0) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to open %s for writing: ", myName, getConfStr("STDERR_LOG")); perror(NULL); exit(ERR_STDERR_LOGFILE_OPEN); } lseek(stderrLogFile, (off_t) 0, SEEK_END); argCount = 0; sprintf(buf, "%s/%s", getConfStr("JAVA_HOME"), getConfStr("JAVA_CMD")); args[argCount++] = strdup(buf); token = strtok(getConfStr("JAVA_ARGS"), " "); while (token != NULL) { if (argCount == MAX_ARGS - 1) { printf(" [ FAILED ]\n"); fprintf (stderr, "Too many args\n"); exit (ERR_TOO_MANY_ARGS); } args[argCount++] = strdup (token); token = strtok(NULL, " "); } if (argCount >= MAX_ARGS - 2) { printf(" [ FAILED ]\n"); fprintf (stderr, "Too many args\n"); exit (ERR_TOO_MANY_ARGS); } args[argCount++] = "-jar"; args[argCount++] = getConfStr("JAR_FILE"); token = strtok(getConfStr("JAR_ARGS"), " "); while (token != NULL) { if (argCount == MAX_ARGS - 1) { printf(" [ FAILED ]\n"); fprintf (stderr, "Too many args\n"); exit (ERR_TOO_MANY_ARGS); } args[argCount++] = strdup (token); token = strtok(NULL, " "); } args[argCount++] = NULL; /* Split this process in two */ pid = fork(); if (pid == -1) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: Unable to fork: "); perror(NULL); exit(ERR_FORK_FAILED); } if (pid == 0) { /* Redirect stdout to log file */ dup2(stdoutLogFile, STDOUT_FILENO); /* Redirect stderr to log file */ dup2(stderrLogFile, STDERR_FILENO); /* TODO: Support redirection of both stdout and stderr to the same file using pipe(2) */ /* Execute the command */ execv(args[0], args); fprintf(stderr, "%s: Unable to start %s %s since '%s/%s -jar %s' in %s: ", myName, getConfStr("APP_TITLE"), getConfStr("PORTVERSION"), getConfStr("JAVA_HOME"), getConfStr("JAVA_CMD"), getConfStr("JAR_FILE"), getConfStr("APP_HOME")); perror(NULL); } else { printf(" [ DONE ]\n"); writePID(file, pid); } } /** * Stops the daemon. */ void stop(void) { int file; int pid; /* Open and read the PID file */ printf(">> Reading PID file (%s)...", getConfStr("PID_FILE")); file = openPIDFile(); pid = readPID(file); printf(">> Checking if %s %s is running...", getConfStr("APP_TITLE"), getConfStr("PORTVERSION")); /* If there is a PID, see if the process still exists */ if (pid != -1) { int result = kill(pid, 0); if (result != 0 && errno == ESRCH) { ftruncate(file, (off_t) 0); pid = -1; } } /* If there is no running process, produce an error */ if (pid == -1) { printf(" [ FAILED ]\n"); fprintf(stderr, "%s: %s %s is currently not running.\n", myName, getConfStr("APP_TITLE"), getConfStr("PORTVERSION")); exit(ERR_NOT_RUNNING); } printf(" [ DONE ]\n"); /* Terminate the process */ killProcess(pid); /* Clear the PID file */ ftruncate(file, (off_t) 0); } /** * Restarts the process. If it not currently running, then it will fail. */ void restart(void) { stop(); start(); } void readConf(char* prog) { FILE* confFile; char* ptr; char confName[80]; char buf[256]; ConfNode* node; ptr = strrchr(prog, '/'); if (ptr == NULL) ptr = prog; else ptr++; myName = strdup(ptr); sprintf (confName, "/usr/local/etc/%s.conf", ptr); printf ("Reading conf file %s...\n", confName); confFile = fopen(confName, "r"); if (confFile == NULL) { fprintf (stderr, "Cannot open configuration file %s ", confName); perror(NULL); exit (ERR_CONF_FILE_OPEN); } while (fgets (buf, sizeof(buf), confFile) != NULL) { if (buf[0] == '#') continue; ptr = strchr(buf, '\n'); if (ptr == NULL) { fprintf (stderr, "Too long line: %s\n", buf); exit(ERR_CONF_FILE_ERROR); } *ptr = '\0'; ptr = strchr(buf, '='); if (ptr == NULL) { fprintf (stderr, "No equal sign found: %s\n", buf); exit (ERR_CONF_FILE_ERROR); } node = malloc(sizeof(ConfNode)); if (node == NULL) { fprintf (stderr, "Out of memory.\n"); exit (ERR_MALLOC); } *ptr = '\0'; node->name = strdup (buf); node->value = strdup(ptr + 1); node->next = confList; confList = node; } fclose (confFile); } char* getConfStr(char* name) { ConfNode* node; node = confList; while (node != NULL) { if (!strcmp(node->name, name)) return node->value; node = node->next; } fprintf (stderr, "Configuration value missing for %s\n", name); exit (ERR_CONFIG_MISSING); return NULL; } int getConfInt(char* name) { return atoi(getConfStr(name)); } --Boundary-00=_dXYe+h5We6YEeP6-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-java" in the body of the message