Added --pidfile= option that can be used even if running in the foreground.

git-svn-id: https://shellinabox.googlecode.com/svn/trunk@223 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
zodiac@gmail.com 2010-09-11 19:32:30 +00:00
parent 61b40ad475
commit bdf1ba75bd
9 changed files with 99 additions and 22 deletions

View file

@ -1,3 +1,8 @@
2010-09-11 Markus Gutschke <markus@shellinabox.com>
* Added --pidfile= option that can be used even if running in the
foreground.
2010-09-04 Markus Gutschke <markus@shellinabox.com> 2010-09-04 Markus Gutschke <markus@shellinabox.com>
* Added an optional on-screen keyboard. Must be activated by the * Added an optional on-screen keyboard. Must be activated by the

View file

@ -153,7 +153,7 @@
#define STDC_HEADERS 1 #define STDC_HEADERS 1
/* Most recent revision number in the version control system */ /* Most recent revision number in the version control system */
#define VCS_REVISION "222" #define VCS_REVISION "223"
/* Version number of package */ /* Version number of package */
#define VERSION "2.10" #define VERSION "2.10"

2
configure vendored
View file

@ -2328,7 +2328,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_compiler_gnu=$ac_cv_c_compiler_gnu
VCS_REVISION=222 VCS_REVISION=223
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF

View file

@ -2,7 +2,7 @@ AC_PREREQ(2.57)
dnl This is the one location where the authoritative version number is stored dnl This is the one location where the authoritative version number is stored
AC_INIT(shellinabox, 2.10, markus@shellinabox.com) AC_INIT(shellinabox, 2.10, markus@shellinabox.com)
VCS_REVISION=222 VCS_REVISION=223
AC_SUBST(VCS_REVISION) AC_SUBST(VCS_REVISION)
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
[Most recent revision number in the version control system]) [Most recent revision number in the version control system])

View file

@ -2384,7 +2384,7 @@ VT100.prototype.toggleCursorBlinking = function() {
}; };
VT100.prototype.about = function() { VT100.prototype.about = function() {
alert("VT100 Terminal Emulator " + "2.10 (revision 222)" + alert("VT100 Terminal Emulator " + "2.10 (revision 223)" +
"\nCopyright 2008-2010 by Markus Gutschke\n" + "\nCopyright 2008-2010 by Markus Gutschke\n" +
"For more information check http://shellinabox.com"); "For more information check http://shellinabox.com");
}; };

View file

@ -358,7 +358,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
}; };
ShellInABox.prototype.about = function() { ShellInABox.prototype.about = function() {
alert("Shell In A Box version " + "2.10 (revision 222)" + alert("Shell In A Box version " + "2.10 (revision 223)" +
"\nCopyright 2008-2010 by Markus Gutschke\n" + "\nCopyright 2008-2010 by Markus Gutschke\n" +
"For more information check http://shellinabox.com" + "For more information check http://shellinabox.com" +
(typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ? (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?

View file

@ -52,6 +52,8 @@
#include <limits.h> #include <limits.h>
#include <locale.h> #include <locale.h>
#include <poll.h> #include <poll.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -94,6 +96,9 @@ static char *cgiSessionKey;
static int cgiSessions; static int cgiSessions;
static char *cssStyleSheet; static char *cssStyleSheet;
static struct UserCSS *userCSSList; static struct UserCSS *userCSSList;
static const char *pidfile;
static sigjmp_buf jmpenv;
static volatile int exiting;
static char *jsonEscape(const char *buf, int len) { static char *jsonEscape(const char *buf, int len) {
static const char *hexDigit = "0123456789ABCDEF"; static const char *hexDigit = "0123456789ABCDEF";
@ -757,6 +762,7 @@ static void usage(void) {
" --localhost-only only listen on 127.0.0.1\n" " --localhost-only only listen on 127.0.0.1\n"
" --no-beep suppress all audio output\n" " --no-beep suppress all audio output\n"
" -n, --numeric do not resolve hostnames\n" " -n, --numeric do not resolve hostnames\n"
" --pidfile=PIDFILE publish pid of daemon process\n"
" -p, --port=PORT select a port (default: %d)\n" " -p, --port=PORT select a port (default: %d)\n"
" -s, --service=SERVICE define one or more services\n" " -s, --service=SERVICE define one or more services\n"
"%s" "%s"
@ -822,6 +828,13 @@ static void destroyExternalFileHashEntry(void *arg, char *key, char *value) {
free(value); free(value);
} }
static void sigHandler(int signo, siginfo_t *info, void *context) {
if (exiting++) {
_exit(1);
}
siglongjmp(jmpenv, 1);
}
static void parseArgs(int argc, char * const argv[]) { static void parseArgs(int argc, char * const argv[]) {
int hasSSL = serverSupportsSSL(); int hasSSL = serverSupportsSSL();
if (!hasSSL) { if (!hasSSL) {
@ -829,7 +842,6 @@ static void parseArgs(int argc, char * const argv[]) {
} }
int demonize = 0; int demonize = 0;
int cgi = 0; int cgi = 0;
const char *pidfile = NULL;
int verbosity = MSG_DEFAULT; int verbosity = MSG_DEFAULT;
externalFiles = newHashMap(destroyExternalFileHashEntry, NULL); externalFiles = newHashMap(destroyExternalFileHashEntry, NULL);
HashMap *serviceTable = newHashMap(destroyServiceHashEntry, NULL); HashMap *serviceTable = newHashMap(destroyServiceHashEntry, NULL);
@ -855,6 +867,7 @@ static void parseArgs(int argc, char * const argv[]) {
{ "localhost-only", 0, 0, 0 }, { "localhost-only", 0, 0, 0 },
{ "no-beep", 0, 0, 0 }, { "no-beep", 0, 0, 0 },
{ "numeric", 0, 0, 'n' }, { "numeric", 0, 0, 'n' },
{ "pidfile", 1, 0, 0 },
{ "port", 1, 0, 'p' }, { "port", 1, 0, 'p' },
{ "service", 1, 0, 's' }, { "service", 1, 0, 's' },
{ "disable-ssl", 0, 0, 't' }, { "disable-ssl", 0, 0, 't' },
@ -894,7 +907,7 @@ static void parseArgs(int argc, char * const argv[]) {
fatal("Only one pidfile can be given"); fatal("Only one pidfile can be given");
} }
if (optarg && *optarg) { if (optarg && *optarg) {
pidfile = strdup(optarg); check(pidfile = strdup(optarg));
} }
} else if (!idx--) { } else if (!idx--) {
// Certificate // Certificate
@ -957,6 +970,9 @@ static void parseArgs(int argc, char * const argv[]) {
if (demonize) { if (demonize) {
fatal("CGI and background operations are mutually exclusive"); fatal("CGI and background operations are mutually exclusive");
} }
if (pidfile) {
fatal("CGI operation and --pidfile= are mutually exclusive");
}
if (port) { if (port) {
fatal("Cannot specify a port for CGI operation"); fatal("Cannot specify a port for CGI operation");
} }
@ -987,7 +1003,7 @@ static void parseArgs(int argc, char * const argv[]) {
check(path = malloc(ptr - optarg + 1)); check(path = malloc(ptr - optarg + 1));
memcpy(path, optarg, ptr - optarg); memcpy(path, optarg, ptr - optarg);
path[ptr - optarg] = '\000'; path[ptr - optarg] = '\000';
file = strdup(ptr + 1); check(file = strdup(ptr + 1));
if (getRefFromHashMap(externalFiles, path)) { if (getRefFromHashMap(externalFiles, path)) {
fatal("Duplicate static-file definition for \"%s\".", path); fatal("Duplicate static-file definition for \"%s\".", path);
} }
@ -1022,6 +1038,18 @@ static void parseArgs(int argc, char * const argv[]) {
} else if (!idx--) { } else if (!idx--) {
// Numeric // Numeric
numericHosts = 1; numericHosts = 1;
} else if (!idx--) {
// Pidfile
if (cgi) {
fatal("CGI operation and --pidfile= are mutually exclusive");
}
if (!optarg || !*optarg) {
fatal("Must specify a filename for --pidfile= option");
}
if (pidfile) {
fatal("Only one pidfile can be given");
}
check(pidfile = strdup(optarg));
} else if (!idx--) { } else if (!idx--) {
// Port // Port
if (port) { if (port) {
@ -1138,21 +1166,23 @@ static void parseArgs(int argc, char * const argv[]) {
_exit(0); _exit(0);
} }
setsid(); setsid();
if (pidfile) { }
if (pidfile) {
#ifndef O_LARGEFILE #ifndef O_LARGEFILE
#define O_LARGEFILE 0 #define O_LARGEFILE 0
#endif #endif
int fd = NOINTR(open(pidfile, int fd = NOINTR(open(pidfile,
O_WRONLY|O_TRUNC|O_LARGEFILE|O_CREAT, O_WRONLY|O_TRUNC|O_LARGEFILE|O_CREAT,
0644)); 0644));
if (fd >= 0) { if (fd >= 0) {
char buf[40]; char buf[40];
NOINTR(write(fd, buf, snprintf(buf, 40, "%d", (int)getpid()))); NOINTR(write(fd, buf, snprintf(buf, 40, "%d", (int)getpid())));
check(!NOINTR(close(fd))); check(!NOINTR(close(fd)));
} } else {
free((char *)pidfile);
pidfile = NULL;
} }
} }
free((char *)pidfile);
} }
static void removeLimits() { static void removeLimits() {
@ -1278,7 +1308,20 @@ int main(int argc, char * const argv[]) {
iterateOverHashMap(externalFiles, registerExternalFiles, server); iterateOverHashMap(externalFiles, registerExternalFiles, server);
// Start the server // Start the server
serverLoop(server); if (!sigsetjmp(jmpenv, 1)) {
// Clean up upon orderly shut down. Do _not_ cleanup if we die
// unexpectedly, as we cannot guarantee if we are still in a valid
// static. This means, we should never catch SIGABRT.
static const int signals[] = { SIGHUP, SIGINT, SIGQUIT, SIGTERM };
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = sigHandler;
sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
for (int i = 0; i < sizeof(signals)/sizeof(*signals); ++i) {
sigaction(signals[i], &sa, NULL);
}
serverLoop(server);
}
// Clean up // Clean up
deleteServer(server); deleteServer(server);
@ -1290,6 +1333,27 @@ int main(int argc, char * const argv[]) {
free(services); free(services);
free(certificateDir); free(certificateDir);
free(cgiSessionKey); free(cgiSessionKey);
if (pidfile) {
// As a convenience, remove the pidfile, if it is still the version that
// we wrote. In general, pidfiles are not expected to be incredibly
// reliable, as there is no way to properly deal with multiple programs
// accessing the same pidfile. But we at least make a best effort to be
// good citizens.
char buf[40];
int fd = open(pidfile, O_RDONLY);
if (fd >= 0) {
ssize_t sz;
NOINTR(sz = read(fd, buf, sizeof(buf)-1));
NOINTR(close(fd));
if (sz > 0) {
buf[sz] = '\000';
if (atoi(buf) == getpid()) {
unlink(pidfile);
}
}
}
free((char *)pidfile);
}
info("Done"); info("Done");
_exit(0); _exit(0);
} }

View file

@ -1,6 +1,6 @@
'\" t '\" t
.\" shellinaboxd.man -- Make command line applications available as AJAX web applications .\" shellinaboxd.man -- Make command line applications available as AJAX web applications
.\" Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com> .\" Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
.\" .\"
.\" This program is free software; you can redistribute it and/or modify .\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License version 2 as .\" it under the terms of the GNU General Public License version 2 as
@ -44,7 +44,7 @@
.\" The most up-to-date version of this program is always available from .\" The most up-to-date version of this program is always available from
.\" http://shellinabox.com .\" http://shellinabox.com
.\" .\"
.TH SHELLINABOXD 1 "Dec 03, 2009" .TH SHELLINABOXD 1 "Sep 11, 2010"
.SH NAME .SH NAME
shellinaboxd \- publish command line shell through AJAX interface shellinaboxd \- publish command line shell through AJAX interface
.SH SYNOPSIS .SH SYNOPSIS
@ -65,6 +65,7 @@ shellinaboxd \- publish command line shell through AJAX interface
[\ \fB--localhost-only\fP\ ] [\ \fB--localhost-only\fP\ ]
[\ \fB--no-beep\fP\ ] [\ \fB--no-beep\fP\ ]
[\ \fB-n\fP\ | \fB--numeric\fP\ ] [\ \fB-n\fP\ | \fB--numeric\fP\ ]
[\ \fB--pidfile=\fP\fIpidfile\fP\ ]
[\ \fB-p\fP\ | \fB--port=\fP\fIport\fP\ ] [\ \fB-p\fP\ | \fB--port=\fP\fIport\fP\ ]
[\ \fB-s\fP\ | \fB--service=\fP\fIservice\fP\ ] [\ \fB-s\fP\ | \fB--service=\fP\fIservice\fP\ ]
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
@ -188,7 +189,8 @@ should be configured to pass through the firewall.
The The
.B --cgi .B --cgi
option is mutually exclusive with the option is mutually exclusive with the
.B --background .BR --background ,
.B --pidfile
and and
.B --port .B --port
options. options.
@ -312,6 +314,12 @@ By default, host names of peers get resolved
before logging them. As DNS look-ups can be expensive, it is possible before logging them. As DNS look-ups can be expensive, it is possible
to request logging of numeric IP addresses, instead. to request logging of numeric IP addresses, instead.
.TP .TP
\fB--pidfile=\fP\fIpidfile\fP
The
.B shellinaboxd
daemon can be configured to store its process identifier in
.IR pidfile .
.TP
\fB-p\fP\ |\ \fB--port=\fP\fIport\fP \fB-p\fP\ |\ \fB--port=\fP\fIport\fP
Unless overridden by this option, the web server listens on port 4200 Unless overridden by this option, the web server listens on port 4200
for incoming HTTP and HTTPS requests. for incoming HTTP and HTTPS requests.
@ -798,7 +806,7 @@ and
.B --user .B --user
options should be used to change to a dedicated user. options should be used to change to a dedicated user.
.SH AUTHOR .SH AUTHOR
Copyright (C) 2008-2009 by Markus Gutschke Copyright (C) 2008-2010 by Markus Gutschke
.RI < "markus@shellinabox.com" >. .RI < "markus@shellinabox.com" >.
.P .P
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify

View file

@ -2384,7 +2384,7 @@ VT100.prototype.toggleCursorBlinking = function() {
}; };
VT100.prototype.about = function() { VT100.prototype.about = function() {
alert("VT100 Terminal Emulator " + "2.10 (revision 222)" + alert("VT100 Terminal Emulator " + "2.10 (revision 223)" +
"\nCopyright 2008-2010 by Markus Gutschke\n" + "\nCopyright 2008-2010 by Markus Gutschke\n" +
"For more information check http://shellinabox.com"); "For more information check http://shellinabox.com");
}; };