[prev in list] [next in list] [prev in thread] [next in thread]
List: freebsd-java
Subject: Re: Specifying jdk for tomcat 4.1.18
From: Ari Suutari <ari.suutari () syncrontech ! com>
Date: 2003-03-20 9:11:57
[Download RAW message or body]
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.
["daemonctl.c" (text/x-csrc)]
/*
* -*- 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 <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
/* 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<count; i++) {
char c = buffer[i];
if (c >= '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));
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-java" in the body of the message
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic