/* -*-c-*-
*
- * $Id: client.c,v 1.6 2001/02/22 09:06:08 mdw Exp $
+ * $Id: client.c,v 1.7 2001/02/22 09:07:54 mdw Exp $
*
* Client for TrIPE
*
/*----- Revision history --------------------------------------------------*
*
* $Log: client.c,v $
+ * Revision 1.7 2001/02/22 09:07:54 mdw
+ * Write a pidfile on request, and delete it when finished.
+ *
* Revision 1.6 2001/02/22 09:06:08 mdw
* Fix logfile rotation to avoid program collapse.
*
/*----- Static variables --------------------------------------------------*/
+static const char *pidfile = 0;
+static const char *logname = 0;
static FILE *logfp = 0;
static unsigned f = 0;
-static const char *logname = 0;
static int fd;
#define f_bogus 1u
static void reap(int sig)
{
- int s;
int e = errno;
- while (waitpid(-1, &s, WNOHANG) > 0)
+ while (waitpid(-1, 0, WNOHANG) > 0)
;
errno = e;
}
logfile(logname);
}
+static void cleanup(void)
+{
+ if (pidfile)
+ unlink(pidfile);
+}
+
+static void sigdie(int sig)
+{
+ cleanup();
+ signal(sig, SIG_DFL);
+ raise(sig);
+}
+
static void version(FILE *fp)
{
pquis(fp, "$, TrIPE version " VERSION "\n");
$ [-w] [-options] [command [args]...]\n\
$ [-Dl] [-f file] [-options]\n\
Options:\n\
- [-s] [-d directory] [-a socket] [-p program] [-S arg,arg,...]\n\
+ [-s] [-d directory] [-a socket] [-P pidfile]\n\
+ [-p program] [-S arg,arg,...]\n\
");
}
-D, --daemon Become a background task after connecting.\n\
-d, --directory=DIR Select current directory [default /var/lib/tripe]\n\
-a, --admin-socket=FILE Select socket to connect to.\n\
+-P, --pidfile=FILE Write process-id to FILE.\n\
\n\
-s, --spawn Start server rather than connecting.\n\
-p, --spawn-path=PATH Specify path to executable.\n\
const char *spawnpath = "tripe";
string_v spawnopts = DA_INIT;
char *p;
+ FILE *pidfp = 0;
ego(argv[0]);
{ "syslog", 0, 0, 'l' },
{ "logfile", OPTF_ARGREQ, 0, 'f' },
{ "warnings", 0, 0, 'w' },
+ { "pidfile", OPTF_ARGREQ, 0, 'P' },
{ 0, 0, 0, 0 }
};
- int i = mdwopt(argc, argv, "hvuDd:a:sp:S:lwf:n", opts, 0, 0, 0);
+ int i = mdwopt(argc, argv, "+hvuDd:a:sp:S:lwf:nP:", opts, 0, 0, 0);
if (i < 0)
break;
switch (i) {
break;
case 'f':
logname = optarg;
- logfile(logname);
f |= f_noinput;
break;
+ case 'P':
+ pidfile = optarg;
+ break;
default:
f |= f_bogus;
break;
exit(EXIT_FAILURE);
}
+ /* --- Set various things up --- */
+
+ if (chdir(dir)) {
+ die(EXIT_FAILURE, "couldn't set `%s' as current directory: %s",
+ dir, strerror(errno));
+ }
+ if (logname)
+ logfile(logname);
+ if (!pidfile && (f & f_daemon) && ((f & f_syslog) || logname))
+ pidfile = "tripectl.pid";
+ if (pidfile && (pidfp = fopen(pidfile, "w")) == 0) {
+ die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
+ pidfile, strerror(errno));
+ }
+ signal(SIGINT, sigdie);
+ signal(SIGQUIT, sigdie);
+ signal(SIGTERM, sigdie);
+ atexit(cleanup);
+
/* --- Connect to the server --- */
if (f & f_spawn) {
sigaction(SIGCHLD, &sa, 0);
DA_UNSHIFT(&spawnopts, (char *)spawnpath);
- if (!(f & f_spawnopts)) {
- DA_PUSH(&spawnopts, "-d");
- DA_PUSH(&spawnopts, (char *)dir);
- DA_PUSH(&spawnopts, "-a");
- DA_PUSH(&spawnopts, (char *)sock);
- }
+ DA_UNSHIFT(&spawnopts, (char *)sock);
+ DA_UNSHIFT(&spawnopts, "-a");
+ DA_UNSHIFT(&spawnopts, "-d.");
DA_PUSH(&spawnopts, 0);
if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfd))
die(EXIT_FAILURE, "error from socketpair: %s", strerror(errno));
if (logfp)
fclose(logfp);
closelog();
+ if (f & f_daemon)
+ u_detach();
execvp(DA(&spawnopts)[0], DA(&spawnopts));
die(127, "couldn't exec `%s': %s", spawnpath, strerror(errno));
}
} else {
struct sockaddr_un sun;
size_t sz = strlen(sock) + 1;
- dstr d = DSTR_INIT;
- dstr_putf(&d, "%s/%s", dir, sock);
- if (d.sz + 1 > sizeof(sun.sun_path))
+ if (sz > sizeof(sun.sun_path))
die(EXIT_FAILURE, "socket name `%s' too long", sock);
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
- memcpy(sun.sun_path, d.buf, d.sz + 1);
- sz = d.sz + offsetof(struct sockaddr_un, sun_path) + 1;
- dstr_destroy(&d);
+ memcpy(sun.sun_path, sock, sz);
+ sz = sz + offsetof(struct sockaddr_un, sun_path);
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
die(EXIT_FAILURE, "error making socket: %s", strerror(errno));
if (connect(fd, (struct sockaddr *)&sun, sz)) {
if (u_daemon())
die(EXIT_FAILURE, "error becoming daemon: %s", strerror(errno));
}
+ if (pidfp) {
+ fprintf(pidfp, "%li", (long)getpid());
+ fclose(pidfp);
+ }
/* --- If we're meant to be interactive, do that --- */