commit 6b70b8c84664f605bf793999e3bb4633bd67a9d4
parent 2fcfb7de1fd14ee9777829b7f873b55b2bb3b313
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:07:54 +0100
1.06
Diffstat:
38 files changed, 508 insertions(+), 263 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,6 +1,32 @@
ChangeLog for Crossroads
------------------------------------------------------------------------------
+1.06 [KK 2006-07-25] Small documentation fix. Embedded c-conf upped to
+ 1.03 (protection from endless recursive directory
+ scans). Optimized http_serve() for short messages (no
+ piggybacking is necessary after the initial chat). Flag -u (user
+ switch) removed; user switching won't work given privileged TCP
+ ports, shared memory access and semaphores all mixed together (or
+ in other words: I'm too lazy right now to make this work
+ elegantly.)
+ Version 1.06 promoted to the next stable.
+
+1.05 [KK 2006-07-12] Restarting heavily sped up, plus it won't affect
+ creation of new listener sockets. Messaging improved, the
+ affected service is reported. Flag -f (foreground mode) removed;
+ this debugging option is no longer useful given the complexity of
+ it all. Added socket shutdowns to interrupt handler
+ (interrupt.c). Fixed up shared memory free ups.
+ THIS VERSION SHOULD MAKE "CROSSROADS RESTART" WORK WELL!
+
+1.04 [KK 2006-06-26] Next development version.
+ [KK 2006-07-03] Fixed http_read(); the # of historic
+ connections ('totuses') would be counted double in sticky HTTP
+ mode.
+ [KK 2006-07-04] Added call to sranddev() to make weighted random
+ dispatching more conforming to the weights (HAVE_SRANDDEV defined
+ in the Makefile when sranddev() is available).
+
1.03 [KK 2006-06-20] Support for older gcc's (incase strlcat() is
missing; added strlcat.c).
Added -lm to linkage flags for fmod().
@@ -11,6 +37,7 @@ ChangeLog for Crossroads
the old code wouldn't correctly see similar high weights.
[KK 2006-06-26] Fixed counting of total nr. of connections in
sticky HTTP mode (as shown with 'crossroads status').
+ This version is tagged as 'stable'.
1.02 [KK 2006-05-11] Next development release.
[KK 2006-05-12] In HTTP mode, the nr of sessions per back end is
diff --git a/doc/compiling.yo b/doc/compiling.yo
@@ -148,7 +148,7 @@ verb(\
controlled by the appropriate statements in the configuration.
it() Determine your 'runlevel': usually 3 when your system is
- running in text-mode only, or 5 when you are a graphical
+ running in text-mode only, or 5 when you are using a graphical
interface. If your runlevel is 3, then:
verb(\
diff --git a/doc/crossroads.html b/doc/crossroads.html
@@ -1,12 +1,12 @@
<a name="defs.yo"></a><html><head>
-<title>Crossroads 1.03</title>
+<title>Crossroads 1.05</title>
<link rel="stylesheet" type="text/css" href="http://www.e-tunity.com/css/yodl.css">
<link rel="stylesheet" type="text/css" href="http://www.e-tunity.com/css/yodl.css">
<link rev="made" href="mailto:info@e-tunity.com">
</head>
<body>
<hr>
-<h1>Crossroads 1.03</h1>
+<h1>Crossroads 1.05</h1>
<h2>Karel Kubat</h2>
<h2>e-tunity</h2><h2>2005, 2006, ff.</h2>
@@ -17,7 +17,7 @@
back ends using 'wakeup calls', detailed status reporting,
'hooks' for special actions when backend calls fail, and much
more. Crossroads is service-independent: it is usable for
- HTTP(S), SSH, SMTP, DNS, etc. In the case of HTTP
+ HTTP/HTTPS, SSH, SMTP, DNS, etc. In the case of HTTP
balancing, Crossroads can provide 'session stickiness' for
back-end processes that need sessions, but aren't
session-aware of other back-ends.</em></blockquote>
@@ -400,7 +400,7 @@ determining your system load.
Second, there's flag <code>-l</code>. This flag selects the 'facility' of
logging and defaults to <code>LOG_DAEMON</code>. You can supply a number
between 0 and 7 to flag <code>-l</code> to select <code>LOG_LOCAL0</code> to
-ttt(LOG_LOCAL7). This would separate the Crossroads-related logging
+<code>LOG_LOCAL7</code>. This would separate the Crossroads-related logging
from other streams. Here's a very short guide; please read your Unix
manpages of <code>syslogd</code> for more information.
<p>
diff --git a/doc/crossroads.man b/doc/crossroads.man
@@ -1,6 +1,6 @@
-.TH "Crossroads 1\&.03" "2005, 2006, ff\&."
+.TH "Crossroads 1\&.05" "2005, 2006, ff\&."
.PP
-.SH "Crossroads 1\&.03"
+.SH "Crossroads 1\&.05"
.SH "Karel Kubat"
.SH "e-tunity"
.SH "2005, 2006, ff\&."
@@ -346,7 +346,7 @@ determining your system load\&.
Second, there\&'s flag \f(CW-l\fP\&. This flag selects the \&'facility\&' of
logging and defaults to \f(CWLOG_DAEMON\fP\&. You can supply a number
between 0 and 7 to flag \f(CW-l\fP to select \f(CWLOG_LOCAL0\fP to
-ttt(LOG_LOCAL7)\&. This would separate the Crossroads-related logging
+\f(CWLOG_LOCAL7\fP\&. This would separate the Crossroads-related logging
from other streams\&. Here\&'s a very short guide; please read your Unix
manpages of \f(CWsyslogd\fP for more information\&.
.PP
diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf
Binary files differ.
diff --git a/doc/crossroads.yo b/doc/crossroads.yo
@@ -7,7 +7,7 @@ abstract(Crossroads is a load balance and fail over utility for TCP
back ends using 'wakeup calls', detailed status reporting,
'hooks' for special actions when backend calls fail, and much
more. Crossroads is service-independent: it is usable for
- HTTP(S), SSH, SMTP, DNS, etc. In the case of HTTP
+ HTTP/HTTPS, SSH, SMTP, DNS, etc. In the case of HTTP
balancing, Crossroads can provide 'session stickiness' for
back-end processes that need sessions, but aren't
session-aware of other back-ends.)
diff --git a/doc/using.yo b/doc/using.yo
@@ -55,7 +55,7 @@ determining your system load.
Second, there's flag tt(-l). This flag selects the 'facility' of
logging and defaults to tt(LOG_DAEMON). You can supply a number
between 0 and 7 to flag tt(-l) to select tt(LOG_LOCAL0) to
-ttt(LOG_LOCAL7). This would separate the Crossroads-related logging
+tt(LOG_LOCAL7). This would separate the Crossroads-related logging
from other streams. Here's a very short guide; please read your Unix
manpages of tt(syslogd) for more information.
diff --git a/etc/Makefile.def b/etc/Makefile.def
@@ -3,14 +3,14 @@
# Versioning. This defines the overall version ID and must match the topmost
# entry in the ChangeLog.
-VER = 1.03
+VER = 1.06
# Default config
DEFAULT_CONF = /etc/crossroads.conf
# The max nr of backends of a given service. This is a fixed number,
# because it defines the size of the shared memory that crossroads claims.
-MAX_BACKEND = 50
+MAX_BACKEND = 10
# Magic mask for shared memory keys.
SHM_MASK = 0x19081962
diff --git a/src/Makefile b/src/Makefile
@@ -43,7 +43,8 @@ DEFS = -DDEFAULT_CONF=\"$(DEFAULT_CONF)\" -DMAX_BACKEND=$(MAX_BACKEND) \
$(shell ../tools/c-conf ifheader stdint.h HAVE_STDINT_H) \
$(shell ../tools/c-conf libfunction flock HAVE_FLOCK) \
$(shell ../tools/c-conf libfunction lockf HAVE_LOCKF) \
- $(shell ../tools/c-conf libfunction strlcat HAVE_STRLCAT)
+ $(shell ../tools/c-conf libfunction strlcat HAVE_STRLCAT) \
+ $(shell ../tools/c-conf libfunction sranddev HAVE_SRANDDEV)
LIBS = $(shell ../tools/c-conf lib ucb nsl pthread socket 2>/dev/null)
diff --git a/src/allocreporter.c b/src/allocreporter.c
@@ -4,17 +4,6 @@ void alloc_reporter (Service *s, int first) {
int shmid;
struct shmid_ds shmbuf;
- if (flag_foreground) {
- /* Fake it! */
- msg ("Obtaining reporting memory for service %s "
- "(in memory segment, NOT in shared memory "
- "since we're in debug mode)",
- s->name);
- servicereport = xmalloc (sizeof(Servicereport));
- memset (servicereport, 0, sizeof(Servicereport));
- return;
- }
-
/* Get an ID to work on, depending on the create mode.
Get a corresponding semaphore too.
*/
diff --git a/src/backendavailable.c b/src/backendavailable.c
@@ -19,7 +19,8 @@ int backend_available () {
(activeservice->backend[i].maxconnections == 0 ||
activeservice->backend[i].maxconnections >
servicereport->backendstate[i].nclients))
- msg ("Found (at least) one available back end");
+ msg ("Service %s: found (at least) one available back end",
+ activeservice->name);
return (1);
}
diff --git a/src/choosebackend.c b/src/choosebackend.c
@@ -6,7 +6,9 @@ void choose_backend () {
tot_weights, lo_val, hi_val, done;
unsigned long long values[MAX_BACKEND], nbest;
unsigned nclients;
+# ifndef HAVE_SRANDDEV
struct timeval tv;
+# endif
/* Check that we're allowed to accept at all. */
if (activeservice->maxconnections &&
@@ -77,9 +79,15 @@ void choose_backend () {
case ds_random:
/* Re-randomize. */
+# ifdef HAVE_SRANDDEV
+ sranddev();
+ msg ("Randomier seeded with randdev");
+# else
gettimeofday (&tv, 0);
srand ((unsigned) tv.tv_usec);
-
+ msg ("Randomizer seeded with %u", (unsigned) tv.tv_usec);
+# endif
+
/* First of all let's see if all the weights are the same. */
tot_weights = 0;
for (i = 0; i < nbackends; i++) {
@@ -144,21 +152,24 @@ void choose_backend () {
k++;
}
- /* Debugging: */
- for (k = 0; k < tot_weights; k++)
- msg ("random: sel_weight[%d] = %d", k, sel_weights[k]);
+ /* Debugging:
+ * for (k = 0; k < tot_weights; k++)
+ * msg ("random: sel_weight[%d] = %d", k, sel_weights[k]);
+ */
- /* Select the next random back end. */
- /*
+ /* Select the next random back end. Algorithm is:
* i = rand() % tot_weights;
* j = sel_weights[i];
* k = backends[j];
* current_backend = k;
- * msg ("i=%d j=%d, k=%d", i, j, k); */
- current_backend = backends[sel_weights[rand() % tot_weights]];
+ * msg ("i=%d j=%d, k=%d", i, j, k);
+ */
+ i = rand() % tot_weights;
+ current_backend = backends[sel_weights[i]];
servicereport->last_backend = current_backend;
free (sel_weights);
- msg ("Chosen backend (weighted random): %d", current_backend);
+ msg ("Chosen backend (weighted random): %d at index %d",
+ current_backend, i);
return;
}
diff --git a/src/copysockets.c b/src/copysockets.c
@@ -21,7 +21,7 @@ void copysockets (int clientsock, int serversock, struct sockaddr_in *client) {
/* Cpio back and forth. */
log_activity_start (client);
-
+
while (1) {
FD_ZERO (&readset);
FD_SET (clientsock, &readset);
@@ -40,7 +40,7 @@ void copysockets (int clientsock, int serversock, struct sockaddr_in *client) {
/* Wait for anything to happen */
nfd = select (FD_SETSIZE, &readset, 0, &exceptset, tvp);
-
+
/* Update the intermediate activity as far as the elapsed time
* is concerned. */
gettimeofday (&tv, 0);
@@ -58,23 +58,20 @@ void copysockets (int clientsock, int serversock, struct sockaddr_in *client) {
servicereport->backendstate[current_backend].nclients--;
unlock_reporter();
log_activity_end (client);
-
+
if (! nfd) {
/* This must be caused by a timeout in select(), otherwise
* the read() below would have returned 0. */
- warning ("Timout in service %s (backend %s) after %d secs",
- activeservice->name,
- activeservice->backend[current_backend].name,
- activeservice->connectiontimeout);
mark_activity (0, 0, st_available);
- error ("Timout in service %s (backend %s) after %d secs",
+ error ("Service %s: Timeout (backend %s) after %d secs",
activeservice->name,
activeservice->backend[current_backend].name,
activeservice->connectiontimeout);
} else {
/* nfd < 0: This is an error condition.
* select() has failed! */
- error ("Failed to wait for network input: %s",
+ error ("Service %s: Failed to wait for network input: %s",
+ activeservice->name,
strerror(errno));
}
}
@@ -118,20 +115,15 @@ void copysockets (int clientsock, int serversock, struct sockaddr_in *client) {
lock_reporter();
servicereport->nclients--;
servicereport->backendstate[current_backend].nclients--;
- unlock_reporter();
+ unlock_reporter();
mark_activity (0, 0, st_available);
close (serversock);
close (clientsock);
log_activity_end (client);
- /* In forked mode, we're done. In foreground mode, RTC. */
- if (flag_foreground) {
- msg ("Successful TCP stop, returning to caller");
- return;
- } else {
- msg ("Successful TCP stop, exiting servicer %d", getpid());
- exit (0);
- }
+ /* We're done. */
+ msg ("Successful TCP stop, exiting servicer %d", getpid());
+ exit (0);
} else if (nread < 0) {
if (src_fd == serversock)
mark_activity (0, 0, st_unavailable);
@@ -142,7 +134,7 @@ void copysockets (int clientsock, int serversock, struct sockaddr_in *client) {
log_activity_end (client);
error ("Read error on connection from %s", src_str);
}
-
+
/* Update the intermediate activity as far as the read bytes
* are concerned. Update traffic / thruput logs. */
// msg ("Read %d bytes from %s", nread, src_str);
diff --git a/src/crossroads.h b/src/crossroads.h
@@ -183,11 +183,11 @@ EXTERN Service *activeservice; /* target service of a daemon */
EXTERN char *config_file; /* config to parse */
EXTERN int current_backend; /* of a given service */
EXTERN int daemonized; /* are we forked off yet */
-EXTERN int flag_foreground; /* flag: don't daemonize */
EXTERN int flag_verbose; /* flag: verbosity */
EXTERN int iflag_present; /* flag: -i present */
EXTERN int interrupted; /* got a signal? */
EXTERN char *laststring; /* semantic lexer value */
+EXTERN int listen_sock; /* servicer listening socket */
EXTERN int log_activity; /* log activy to syslog? */
EXTERN int log_facility; /* openlog(3) facility, -l flag */
EXTERN int logstarted; /* was syslog() called yet? */
@@ -200,7 +200,6 @@ EXTERN int semid; /* semaphore ID */
EXTERN Service *service; /* service descriptions */
EXTERN Servicereport *servicereport; /* reporter in shared mem */
EXTERN char *state_to_string_map[]; /* backend states as strings */
-EXTERN int uid; /* UID to assume */
EXTERN FILE *yyin; /* config file handle */
EXTERN int yylineno; /* input line number */
EXTERN char *yyerrmsg; /* parsing error msg */
diff --git a/src/deallocreporter.c b/src/deallocreporter.c
@@ -10,24 +10,25 @@ void dealloc_reporter (Service *s) {
* then ignore the error. The true handler will have already released it.
*/
if ( (shmid = shmget (s->shmkey, sizeof(Servicereport),
- 0644) ) >= 0)
+ 0644) ) >= 0) {
msg ("Got existing shm at id %d", shmid);
- else if (program_stage != stage_main)
- error ("Cannot get shared memory for service %s (key %d: %s)",
- s->name, s->shmkey, strerror(errno));
- else
- return;
-
- /* Mark to be released. If this fails and if we're stage 0,
- * then ignore.
- */
- if (shmctl (shmid, IPC_RMID, 0) < 0 && program_stage != stage_main)
- error ("Cannot mark shared memory as destructable: %s "
- "NOTE: Root will need to 'ipcrm -m %d' and 'ipcrm -s %d' "
- "to clean up!",
- strerror(errno), shmid, semid);
- if (semctl (semid, 0, IPC_RMID) < 0 && program_stage != stage_main)
- error ("Cannot remove semaphore: %s "
- "NOTE: Root will need to 'ipcrm -s %d' to clean up!",
- semid);
+ /* Mark to be released. If this fails then warn. */
+ if (shmctl (shmid, IPC_RMID, 0) < 0 && program_stage != stage_main)
+ warning ("WARNING: Cannot mark shared memory as destructable: %s "
+ "Root might need to 'ipcrm -m %d' and "
+ "'ipcrm -s %d' to clean up!",
+ strerror(errno), shmid, semid);
+ if (semctl (semid, 0, IPC_RMID) < 0 && program_stage != stage_main)
+ warning ("WARNING: Cannot remove semaphore: %s "
+ "Root might need to 'ipcrm -s %d' to clean up!",
+ strerror(errno), semid);
+ }
+ else if (program_stage != stage_main) {
+ /* Errno 2 means that the shm block was already removed (by a
+ * different listener) Don't warn if that's the case.
+ */
+ if (errno != 2)
+ warning ("Cannot get shared memory for service %s (key %d: %d/%s)",
+ s->name, s->shmkey, errno, strerror(errno));
+ }
}
diff --git a/src/forktcpservicer.c b/src/forktcpservicer.c
@@ -3,9 +3,6 @@
int fork_tcp_servicer (int to_backend) {
int pid, i;
- if (flag_foreground)
- return (0);
-
if ( (pid = fork()) < 0 )
/* Fork failure */
error ("Failed to fork: %s", strerror(errno));
diff --git a/src/httpread.c b/src/httpread.c
@@ -70,8 +70,6 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) {
if (!isclient)
servicereport->backendstate[current_backend].nclients--;
unlock_reporter();
- if (!isclient)
- mark_activity (0, 0, st_available);
if (nread < 0)
warning ("Failed to read HTTP input: %s", strerror(errno));
else
@@ -109,8 +107,6 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) {
if (!isclient)
servicereport->backendstate[current_backend].nclients--;
unlock_reporter();
- if (!isclient)
- mark_activity (0, 0, st_available);
msg ("HTTP read: complete message (%d bytes) '%s'",
*buflen, *bufp);
return;
diff --git a/src/httpserve.c b/src/httpserve.c
@@ -20,7 +20,7 @@ void http_serve (int clientsock, struct sockaddr_in *client) {
*/
if (is_continuation)
log_activity_continuation (client);
-
+
if (http_write (serversock, firstbuf, buflen)) {
mark_activity (0, 0, st_unavailable);
error ("Failed to send data to backend '%s'",
@@ -37,17 +37,19 @@ void http_serve (int clientsock, struct sockaddr_in *client) {
http_set_sticky_cookie (&secondbuf, &buflen);
if (http_write (clientsock, secondbuf, buflen))
error ("Failed to send data to client");
- free (secondbuf);
}
- /* Now we have a client and server socket, possibly with a
- * session cookie in the chat. Piggyback to & fro. */
- copysockets (clientsock, serversock, client);
-
+ /* Now we might have to piggyback to and fro -- tho only if the
+ * HTTP chat wasn't done yet. */
+ if (http_complete (secondbuf, buflen))
+ mark_activity (0, 0, st_available);
+ else
+ copysockets (clientsock, serversock, client);
+ free (secondbuf);
+
/* Normal shutdown: TCP traffic done. */
msg ("Normal HTTP stop.");
close (serversock);
close (clientsock);
- if (! flag_foreground)
- exit (0);
+ exit (0);
}
diff --git a/src/interrupt.c b/src/interrupt.c
@@ -6,24 +6,29 @@ void interrupt (int sig) {
switch (program_stage) {
case stage_waiting:
- warning ("LISTENER: "
- "Caught signal %d, freeing reporter and stopping",
- sig);
- dealloc_reporter (activeservice);
- exit (1);
+ warning ("Service %s: listener caught signal %d, "
+ "closing socket %d and exiting",
+ activeservice->name, sig, listen_sock);
+ if (shutdown (listen_sock, SHUT_RDWR))
+ error ("Service %s: can't shut down server-side socket %d: %s",
+ activeservice->name, listen_sock, strerror(errno));
+ if (close (listen_sock))
+ error ("Service %s: can't close socket %d: %s",
+ activeservice->name, listen_sock, strerror(errno));
+ exit (0);
case stage_serving:
- warning ("CONNECTION SERVICER: "
- "Caught signal %d, will stop after servicing connection",
- sig);
+ warning ("Service %s: servicer caught signal %d, "
+ "will exit after servicing my connection",
+ activeservice->name, sig);
break;
case stage_retrying:
- warning ("WAKEUP HANDER: "
- " Caught signal %d, will stop waking up backend and exit",
- sig);
- exit (1);
+ warning ("Service %s: wakeup handler caught signal %d, "
+ "stopping wake ups and exiting",
+ activeservice->name, sig);
+ exit (0);
default:
- msg ("Caught signal %d in program stage %s", sig,
+ msg ("Caught signal %d in program stage %s, exiting", sig,
stage_to_string (program_stage));
- exit (1);
+ exit (0);
}
}
diff --git a/src/lockreporter.c b/src/lockreporter.c
@@ -15,9 +15,6 @@ void lock_reporter() {
}
};
- if (flag_foreground)
- return;
-
/* msg ("Locking reporter memory"); */
if ( (!warning_issued++) && (semop (semid, buf, 2) < 0) ) {
warning ("Failed to lock reporter memory (stage %s): %s",
diff --git a/src/main.c b/src/main.c
@@ -52,7 +52,7 @@ int main (int argc, char **argv) {
/* Parse options. */
config_file = DEFAULT_CONF;
- while ( (opt = getopt (argc, argv, "?c:fhvi:u:Val:")) > 0 )
+ while ( (opt = getopt (argc, argv, "?c:fhvi:Val:")) > 0 )
switch (opt) {
case 'a':
log_activity++;
@@ -60,9 +60,6 @@ int main (int argc, char **argv) {
case 'c':
config_file = optarg;
break;
- case 'f':
- flag_foreground++;
- break;
case 'v':
flag_verbose++;
break;
@@ -99,12 +96,6 @@ int main (int argc, char **argv) {
usage();
}
break;
- case 'u':
- if (! (passwd = getpwnam (optarg)) )
- error ("Cannot fetch information for user '%s': %s",
- optarg, strerror(errno));
- uid = passwd->pw_uid;
- break;
case 'V':
puts (VER);
exit (0);
diff --git a/src/makesocket.c b/src/makesocket.c
@@ -7,11 +7,13 @@ int make_socket (int port, char const *ipaddr) {
/* Create the socket. */
if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0) {
- warning ("Cannot create network socket: %s", strerror(errno));
+ warning ("Service %s: cannot create network socket: %s",
+ activeservice->name, strerror(errno));
return (-1);
}
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
- warning ("Cannot set socket options: %s", strerror(errno));
+ warning ("Service %s: cannot set socket options: %s",
+ activeservice->name, strerror(errno));
close (sock);
return (-2);
}
@@ -22,20 +24,23 @@ int make_socket (int port, char const *ipaddr) {
/* Propagate 'bindto' if given. */
if (strcasecmp (ipaddr, "any")) {
- msg ("Creating socket for IP address '%s'", ipaddr);
+ msg ("Service %s: creating socket for IP address '%s'",
+ activeservice->name, ipaddr);
if ( (name.sin_addr.s_addr = inet_addr (ipaddr)) == INADDR_NONE ) {
close (sock);
- error ("Cannot convert address '%s' to network bytes",
- ipaddr);
+ error ("Service %s: cannot convert address '%s' to network bytes",
+ activeservice->name, ipaddr);
}
} else {
- msg ("Creating socket for all interfaces");
+ msg ("Service %s: creating socket for all interfaces",
+ activeservice->name);
name.sin_addr.s_addr = htonl (INADDR_ANY);
}
/* Finallly, bind the socket. */
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
- warning ("Cannot bind socket to port %d: %s", port, strerror(errno));
+ warning ("Service %s: cannot bind socket to port %d: %s",
+ activeservice->name, port, strerror(errno));
close (sock);
return (-3);
}
diff --git a/src/markactivity.c b/src/markactivity.c
@@ -16,8 +16,7 @@ void mark_activity (unsigned long long nbytes, double nsec,
/* Handle the decays of all other back ends */
for (i = 0; i < activeservice->nbackend; i++) {
- if (i != current_backend &&
- activeservice->backend[i].decay) {
+ if (i != current_backend && activeservice->backend[i].decay) {
if (activeservice->dispatchover) {
servicereport->backendstate[i].avg_nbytes *=
(100 - activeservice->backend[i].decay);
diff --git a/src/restart.c b/src/restart.c
@@ -17,8 +17,9 @@ void restart (int ac, char **av) {
"Crossroads may be in an unstable state, fix by hand!",
cmd);
- /* Wait a few secs to allow the listening socket to free up. */
- sleep (1);
+ /* Wait a few secs to allow the listening socket to free up.
+ * sleep (1);
+ */
/* Now run the 'start' action */
org_argv[org_argc - 1] = "start";
diff --git a/src/runservice.c b/src/runservice.c
@@ -1,56 +1,51 @@
#include "crossroads.h"
void runservice () {
- int listen_sock, pid;
+ int pid;
- msg ("Service: %s (on port %d)",
+ msg ("Service %s (on port %d): STARTING",
activeservice->name, activeservice->port);
/* Allocate the shared mem segment. */
alloc_reporter(activeservice, 1);
- /* Now if required, go into the background. */
- if (!flag_foreground) {
-
- if ( (pid = fork()) < 0 ) {
- /* Fork failed */
- error ("Fork failure: %s", strerror(errno));
- } else if (pid) {
- /* Parent branch */
- msg ("Service %s detached as PID %d",
- activeservice->name, pid);
- return;
- } else {
- /* Child branch */
- if (uid) {
- if (seteuid(uid))
- error ("Cannot assume effective uid %d: %s",
- uid, strerror(errno));
- }
-
- set_program_title ("service %s listening", activeservice->name);
- close (0);
- close (1);
- close (2);
- daemonized++;
- if ( (open ("/dev/null", O_RDONLY) < 0) ||
- (open ("/dev/null", O_WRONLY) < 0) ||
- (open ("/dev/null", O_WRONLY) < 0) )
- error ("Failed to reopen stdin/out/err on /dev/null");
- if (setsid() < 0)
- error ("Failed to become seesion leader");
+ /* Go into the background. */
+ if ( (pid = fork()) < 0 ) {
+ /* Fork failed */
+ error ("Service %s: fork failure: %s",
+ activeservice->name, strerror(errno));
+ } else if (pid) {
+ /* Parent branch */
+ msg ("Service %s: detached as PID %d",
+ activeservice->name, pid);
+ return;
+ } else {
+ /* Child branch */
+ set_program_title ("service %s listening", activeservice->name);
+ close (0);
+ close (1);
+ close (2);
+ daemonized++;
+ if ( (open ("/dev/null", O_RDONLY) < 0) ||
+ (open ("/dev/null", O_WRONLY) < 0) ||
+ (open ("/dev/null", O_WRONLY) < 0) )
+ error ("Service %s: "
+ "failed to reopen stdin/out/err on /dev/null",
+ activeservice->name);
+ if (setsid() < 0)
+ error ("Service %s: failed to become seesion leader",
+ activeservice->name);
- /* Store our pid, so that 'crossroads stop' may kill us. */
- lock_reporter();
- servicereport->pid = getpid();
- unlock_reporter();
+ /* Store our pid, so that 'crossroads stop' may kill us. */
+ lock_reporter();
+ servicereport->pid = getpid();
+ unlock_reporter();
- /* Promote verbosity. */
- flag_verbose = activeservice->verbosity;
-
- /* We've forked for the first time */
- program_stage = stage_waiting;
- }
+ /* Promote verbosity. */
+ flag_verbose = activeservice->verbosity;
+
+ /* We've forked for the first time */
+ program_stage = stage_waiting;
}
/* In 'forever' mode, we create a server-side socket and ask tcpserve()
@@ -64,7 +59,9 @@ void runservice () {
/* Create the socket, bind to port. */
if ( (listen_sock = make_socket (activeservice->port,
activeservice->bind)) < 0 ) {
- warning ("Listening socket creation failed.. will retry");
+ warning ("Service %s: "
+ "listening socket creation failed.. will retry",
+ activeservice->name);
/* We wait here for some time, to let the system regain
* equilibrium. Something's really afoot, so let's not retry
@@ -73,7 +70,8 @@ void runservice () {
continue;
}
- msg ("Server-side network socket: %d", listen_sock);
+ msg ("Service %s: server-side network socket: %d",
+ activeservice->name, listen_sock);
/* Start serving the port! */
tcpserve (listen_sock);
@@ -81,15 +79,16 @@ void runservice () {
/* tcpserve() returned -- must be because this service is out
* of back ends */
if (shutdown (listen_sock, SHUT_RDWR))
- error ("Failed to shut down server-side socket %d: %s",
- listen_sock, strerror(errno));
+ error ("Service %s: "
+ "failed to shut down server-side socket %d: %s",
+ activeservice->name, listen_sock, strerror(errno));
if (close (listen_sock))
- error ("Failed to close server-side socket %d: %s",
- listen_sock, strerror(errno));
+ error ("Service %s: failed to close server-side socket %d: %s",
+ activeservice->name, listen_sock, strerror(errno));
}
- msg ("Taking a nap...");
+ msg ("Service %s: taking a nap...", activeservice->name);
sleep (SLEEP_TIME);
}
}
diff --git a/src/sample.conf b/src/sample.conf
@@ -10,7 +10,7 @@
* over a couple of webserver back ends.
*/
service www {
-
+
/* Port on which we'll listen in this service: required. */
port 8000;
@@ -18,15 +18,15 @@ service www {
* Alternatively you can state an explicit IP address, such as
* 127.0.0.1; that would bind the service only to 'localhost'. */
bindto any;
-
- /* Verbose reporting or not. Default is off. */
+
+ /* Verbose reporting or not. Default is off. */
verbosity on;
/* Service type: 'http' or 'any'. With 'http' you can make sessions
* "stick" to a once selected back end. If you don't need stickiness,
* use 'any' which is the default. */
type any;
-
+
/* Dispatching mode, or: How to select a back end for an incoming
* request. Possible values:
* roundrobin: just the next back end in line
@@ -40,8 +40,8 @@ service www {
* byduration: The backend that was active for the shortest time
* is the next in line. As a modifier you can say e.g.
* byduration of 10 to compute over the last 10 connections.
- * byconnections: The back end with the least number of active
- * connections is the next in line.
+ * byconnections: The back end with the least number of active
+ * connections is the next in line.
* byorder: The first available back end is always taken.
*/
dispatchmode byduration over 5;
@@ -50,12 +50,12 @@ service www {
* backend has woken up.
*/
revivinginterval 5;
-
+
/* TCP backlog of connections. Default is 0 (no backlog, one
* connection may be active).
*/
backlog 5;
-
+
/* For status reporting: a shared memory key. Default is the same
* as the port number, OR-ed by a magic number.
*/
@@ -89,7 +89,7 @@ service www {
* end.
*/
decay 10;
-
+
/* To see what's happening in /var/log/messages: */
verbosity on;
}
@@ -106,8 +106,8 @@ service www {
/* Decay */
decay 10;
- /* Performance related */
- throughputlog /tmp/backend.2.perflog;
+ /* Performance related */
+ throughputlog /tmp/backend.2.perflog;
/* Event triggers for system commands upon succesful activation
* and upon failure.
@@ -126,27 +126,27 @@ service www {
verbosity on;
decay 10;
trafficlog /tmp/backend.3.log;
- maxconnections 10;
+ maxconnections 10;
}
}
/* Another example: SSH login failover. */
service ssh {
port 2222; // Incoming port
- type any; // Generic TCP service
+ type any; // Generic TCP service
verbosity on; // Let's be verbose
shmkey 2222; // Shared memory related
connectiontimeout 30; // Auto-logout after 30 secs
dispatchmode bysize over 1; // Least bytes = least active,
// only last connection matters
maxconnections 1; // 1 concurrent login
-
+
backend ssh_1 { // First back end
server sshserver1:22;
verbosity on;
onfailure echo 'SSH failure on sshserver1' | mail root;
}
-
+
backend ssh_2 { // Second back end
server sshserver2:22;
verbosity on;
@@ -162,23 +162,22 @@ service balancedapp {
port 8001;
type stickyhttp;
backend app1 {
- server appserver1:8080;
- /* If 'BalancerID=a' is already in the browser's request, then
- * the request automatically goes to this backend */
- stickycookie BalancerID=a;
- /* The server return is enriched with the following cookie
- * instruction (note that this matches 'stickycookie' above) */
- insertcookie "BalancerID=a; Path=/";
+ server appserver1:8080;
+ /* If 'BalancerID=a' is already in the browser's request, then
+ * the request automatically goes to this backend */
+ stickycookie BalancerID=a;
+ /* The server return is enriched with the following cookie
+ * instruction (note that this matches 'stickycookie' above) */
+ insertcookie "BalancerID=a; Path=/";
}
backend app2 {
- server appserver2:8080;
- stickycookie BalancerID=b;
- insertcookie "BalancerID=b; Path=/";
+ server appserver2:8080;
+ stickycookie BalancerID=b;
+ insertcookie "BalancerID=b; Path=/";
}
backend app3 {
- server appserver3:8080;
- stickycookie BalancerID=c;
- insertcookie "BalancerID=c; Path=/";
+ server appserver3:8080;
+ stickycookie BalancerID=c;
+ insertcookie "BalancerID=c; Path=/";
}
}
-
diff --git a/src/serve.c b/src/serve.c
@@ -12,7 +12,7 @@ void serve (int ac, char **av) {
* space on the commanedline.
*/
# if SET_PROC_TITLE_BY_ARGV == 1
- if (! flag_foreground && ! iflag_present) {
+ if (! iflag_present) {
char **argv = xmalloc ( (org_argc + 2) * sizeof(char*));
int i;
@@ -33,10 +33,6 @@ void serve (int ac, char **av) {
# endif
for (i = 0; i < nservice; i++) {
- /* With -f flag, don't run second and next services. */
- if (i && flag_foreground)
- break;
-
/* Start the service. */
activeservice = service + i;
runservice ();
diff --git a/src/tcpserve.c b/src/tcpserve.c
@@ -7,7 +7,7 @@ void tcpserve (int server_sock) {
static int wakeup_started = 0;
/* Set up our signal handlers. */
- if (!flag_foreground && !wakeup_started++) {
+ if (!wakeup_started++) {
/* Interruption signals */
for (i = 0; relevant_sigs[i]; i++)
signal (relevant_sigs[i], interrupt);
@@ -19,17 +19,19 @@ void tcpserve (int server_sock) {
set_program_title ("wakeup for %s", activeservice->name);
wakeup_handler();
} else {
- msg ("Started wakeup handler at pid %d", pid);
+ msg ("Service %s: started wakeup handler at pid %d",
+ activeservice->name, pid);
servicereport->rev_pid = pid;
}
}
}
- msg ("Awaiting activity on port %d (socket fd %d)",
- activeservice->port, server_sock);
+ msg ("Service %s: awaiting activity on port %d (socket fd %d)",
+ activeservice->name, activeservice->port, server_sock);
if (listen (server_sock, activeservice->backlog + 1) < 0)
- error ("Failed to listen to server_socket: %s", strerror(errno));
+ error ("Service %s: failed to listen to server_socket: %s",
+ activeservice->name, strerror(errno));
/* Avoid zombies. */
signal (SIGCHLD, SIG_IGN);
@@ -42,15 +44,15 @@ void tcpserve (int server_sock) {
FD_ZERO (&set);
FD_SET (server_sock, &set);
if (select (FD_SETSIZE, &set, 0, 0, 0) < 0)
- error ("Error while waiting for activity: %d (%s)",
- errno, strerror(errno));
+ error ("Service %s: error while waiting for activity: %d (%s)",
+ activeservice->name, errno, strerror(errno));
/* Accept the client-side connection. */
size = sizeof(clientname);
if ( (new = accept (server_sock, (struct sockaddr *) &clientname,
(socklen_t *) &size)) < 0 )
- error ("Failure while accepting on server socket: %s",
- strerror(errno));
+ error ("Service %s: failure while accepting on server socket: %s",
+ activeservice->name, strerror(errno));
msg ("Connect on service %s from %s",
activeservice->name,
@@ -70,7 +72,8 @@ void tcpserve (int server_sock) {
* create a new one.
*/
if (! backend_available()) {
- warning ("No back ends available");
+ warning ("Service %s: no back ends available",
+ activeservice->name);
close (new);
return;
}
@@ -86,7 +89,8 @@ void tcpserve (int server_sock) {
}
/* Show what's happening. */
- msg ("Trying back end %s, port %d",
+ msg ("Service %s: trying back end %s, port %d",
+ activeservice->name,
activeservice->backend[current_backend].server,
activeservice->backend[current_backend].port);
@@ -95,7 +99,8 @@ void tcpserve (int server_sock) {
* In the loop we may need to decide to return after all. */
if ( (backend_sock = backend_connect(0)) < 0 ) {
sysrun (activeservice->backend[current_backend].onfailure);
- warning ("Failed to connect to server %s:%d",
+ warning ("Service %s: failed to connect to server %s:%d",
+ activeservice->name,
activeservice->backend[current_backend].server,
activeservice->backend[current_backend].port);
continue;
diff --git a/src/unlockreporter.c b/src/unlockreporter.c
@@ -9,9 +9,6 @@ void unlock_reporter() {
0, /* no special flags */
};
- if (flag_foreground)
- return;
-
/* msg ("UnLocking reporter memory"); */
if ( (! warning_issued++) && (semop (semid, &buf, 1) < 0) ) {
warning ("Failed to unlock reporter memory (stage %s): %s",
diff --git a/src/usage.txt b/src/usage.txt
@@ -22,21 +22,10 @@ Supported flags:
-a: logs starting and finishing activity to syslog
-c CONFIG: Uses the named configuration, instead of the default
%s
- -f: With '(re)start', causes crossroads to stay in the foreground
- instead of daemonizing. Useful for debugging with -v. No
- 'status' reporting is possible, no wakeup handlers will run.
-l FAC: Specifies the openlog(3) facility to use when
- logging. Default is LOG_DAEMON. Allowed values are 0..7
- for LOG_LOCAL0 to LOG_LOCAL7.
- -u USER: With '(re)start', causes the daemons to run under the
- permissions of the stated user. Unused when combined with -f.
- -v: Enables verbosity upon startup and, when used with -f, in the
- services. Normally the services verbosity is controlled via
- 'verbosity' statements in the configuration.
- -V: Shows the version ID and stops.
+ logging. Default is LOG_DAEMON. Allowed values are 0..7
+ for LOG_LOCAL0 to LOG_LOCAL7.
+ -v: Enables verbosity upon startup. Other verbosity (services
+ and back ends) is controlled in the configuration.
+ -V: Shows the version ID and stops.
-?, -h: Shows this message.
-
-NOTE: Stopping, restarting and status reporting depends on the
-configuration that was in use when crossroads was started. Therefore,
-before adding or removing services in the configuration, 'stop' the
-running services first.
diff --git a/src/xmalloc.c b/src/xmalloc.c
@@ -1,9 +1,5 @@
#include "crossroads.h"
void *xmalloc (unsigned sz) {
- void *ret;
-
- if (! (ret = malloc (sz)) )
- error ("Out of memory (while allocating %u bytes)", sz);
- return (ret);
+ return (xrealloc (0, sz));
}
diff --git a/src/xrealloc.c b/src/xrealloc.c
@@ -1,12 +1,22 @@
#include "crossroads.h"
-void *xrealloc (void *what, unsigned sz) {
+void *xrealloc (void *block, unsigned sz) {
+ void *newblock;
+
+ // msg ("Realloc: block=%x, sz=%u", block, sz);
if (! sz) {
- free (what);
- return (0);
+ free (block);
+ newblock = 0;
+ // msg ("Realloc: freed %x", block);
+ } else if (!block) {
+ if (! (newblock = malloc (sz)) )
+ error ("Out of memory (while allocating %u bytes)", sz);
+ // msg ("Realloc: malloc'd %x (%u bytes)", newblock, sz);
+ } else {
+ if (! (newblock = realloc (block, sz)) )
+ error ("Out of memory (while increasing block to %u bytes)", sz);
+ // msg ("Realloc'd %x to %x (%u bytes)", block, newblock, sz);
}
- if (! (what = realloc (what, sz)) )
- error ("Out of memory (while increasing block to %u bytes)", sz);
- return (what);
+ return (newblock);
}
diff --git a/test/client b/test/client
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use strict;
+use Socket;
+
+if ($#ARGV != 1) {
+ die <<"ENDUSAGE";
+
+Usage: client host port
+
+ENDUSAGE
+}
+
+my ($host, $port) = @ARGV;
+
+print ("Starting client loop to query $host:$port.. press ^C to stop\n");
+sleep (1);
+
+my %hits = (a => 0, b => 0, c => 0, unknown => 0, errors => 0);
+
+while (1) {
+ open (my $if, "wget -vSO- http://$host:$port 2>&1 |")
+ or die ("Can't start wget: $!\n");
+ my ($a, $b, $c, $unk, $err);
+ $err = 1;
+ while (my $msg = <$if>) {
+ chomp ($msg);
+ # print ("Server says: [$msg]\n");
+ if ($msg =~ /HTTP.*200 OK/ or $msg =~ /Hello World/) {
+ $err = 0;
+ } elsif ($msg =~ /Backend_A/) {
+ $a = 1;
+ } elsif ($msg =~ /Backend_B/) {
+ $b = 1;
+ } elsif ($msg =~ /Backend_C/) {
+ $c = 1;
+ }
+ }
+ close ($if);
+
+ $unk = 1 if ($a == 0 and $b == 0 and $c == 0);
+
+ $hits{a} += $a;
+ $hits{b} += $b;
+ $hits{c} += $c;
+ $hits{unknown} += $unk;
+ $hits{errors} += $err;
+
+ for my $k (sort (keys (%hits))) {
+ print ("$k=$hits{$k} ");
+ }
+ print ("\n");
+
+ # sleep (1);
+ select (undef, undef, undef, 0.2);
+};
diff --git a/test/server b/test/server
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+
+use strict;
+use Socket;
+use POSIX;
+
+# Verbose messaging
+sub msg {
+ print STDERR ("server: ", @_);
+}
+
+# Child process catcher
+sub reaper {
+ while ((my $waitedpid = waitpid(-1,WNOHANG)) > 0) {
+ msg ("Child $waitedpid done",
+ ($? ? " with exit $?" : ''),
+ "\n");
+ }
+ $SIG{CHLD} = \&reaper;
+}
+
+# Connection handler
+sub handleconnection () {
+ my $pid;
+
+ # Daemonize
+ if (!defined ($pid = fork())) {
+ msg ("Can't fork: $!\n");
+ return;
+ } elsif ($pid) {
+ # Parent branch
+ msg ("Connection handler started as pid $pid\n");
+ return;
+ }
+
+ # Child branch
+ select Client;
+ $| = 1;
+
+ my $msg = "Hello World!\n";
+ print ("HTTP/1.0 200 OK\r\n",
+ "Content-length: ", length($msg), "\r\n",
+ "\r\n",
+ $msg);
+ exit (0);
+}
+
+# Daemon server
+sub serve ($) {
+ my $port = shift;
+
+ # Create the tcp service.
+ socket (Server, PF_INET, SOCK_STREAM, getprotobyname ('tcp'))
+ or die ("Can't create server socket: $!\n");
+ setsockopt (Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
+ or die ("Can't set socket options: $!\n");
+ bind (Server, sockaddr_in ($port, INADDR_ANY))
+ or die ("Can't bind to port: $!\n");
+ listen (Server, SOMAXCONN)
+ or die ("Can't listen to socket: $!\n");
+ msg ("Server started on port $port.\n");
+
+ $SIG{CHLD} = \&reaper;
+ $SIG{INT} = sub {
+ msg ("Interrupt caught, terminating..\n");
+ exit(0);
+ };
+
+ while (1) {
+ for (my $waitedpid = 0;
+ (my $paddr = accept (Client, Server)) || $waitedpid;
+ $waitedpid = 0, close (Client)) {
+ next if ($waitedpid and not $paddr);
+ my ($port, $iaddr) = sockaddr_in ($paddr);
+ my $name = gethostbyaddr ($iaddr, AF_INET);
+
+ msg ("Connection from $name/", inet_ntoa ($iaddr), ":$port\n");
+
+ handleconnection ();
+ }
+ }
+}
+
+# Main starts here
+if ($#ARGV != 0) {
+ die <<"ENDUSAGE";
+
+Usage: server portnr
+
+ENDUSAGE
+}
+
+serve (shift (@ARGV));
+
diff --git a/test/t1.conf b/test/t1.conf
@@ -0,0 +1,36 @@
+service test {
+ port 10001;
+ type stickyhttp;
+ bindto any;
+ revivinginterval 5;
+ dispatchmode bysize;
+ connectiontimeout 600;
+ verbosity on;
+
+ backend a {
+ server localhost;
+ port 10000;
+ weight 2;
+ decay 5;
+ stickycookie BalancerID=Backend_A;
+ insertcookie "BalancerID=Backend_A; Path=/";
+ }
+
+ backend b {
+ server localhost;
+ port 10000;
+ weight 2;
+ decay 5;
+ stickycookie BalancerID=Backend_B;
+ insertcookie "BalancerID=Backend_B; Path=/";
+ }
+
+ backend c {
+ server localhost;
+ port 10000;
+ weight 3;
+ decay 5;
+ stickycookie BalancerID=Backend_C;
+ insertcookie "BalancerID=Backend_C; Path=/";
+ }
+}
diff --git a/test/t2.conf b/test/t2.conf
@@ -0,0 +1,36 @@
+service test {
+ port 10001;
+ type stickyhttp;
+ bindto any;
+ revivinginterval 5;
+ dispatchmode random;
+ connectiontimeout 600;
+ verbosity on;
+
+ backend a {
+ server localhost;
+ verbosity on;
+ port 10000;
+ weight 2;
+ stickycookie BalancerID=Backend_A;
+ insertcookie "BalancerID=Backend_A; Path=/";
+ }
+
+ backend b {
+ server localhost;
+ verbosity on;
+ port 10000;
+ weight 3;
+ stickycookie BalancerID=Backend_B;
+ insertcookie "BalancerID=Backend_B; Path=/";
+ }
+
+ backend c {
+ server localhost;
+ verbosity on;
+ port 10000;
+ weight 3;
+ stickycookie BalancerID=Backend_C;
+ insertcookie "BalancerID=Backend_C; Path=/";
+ }
+}
diff --git a/test/t3.conf b/test/t3.conf
@@ -0,0 +1,13 @@
+/* Another testing scenario.
+ * This one forwards port 23 to localhost:22 (sshd), and logs out
+ * after 1 minute of inactivity. */
+
+service ssh {
+ port 23;
+ connectiontimeout 60;
+ verbosity true;
+ backend a {
+ verbosity true;
+ server localhost:22;
+ }
+}
diff --git a/tools/c-conf b/tools/c-conf
@@ -4,7 +4,10 @@ use strict;
use Getopt::Std;
# Globals
-my $VER = "1.01";
+my $VER = "1.03";
+# 1.03 [KK 2006-07-19] 'subfiles' keeps track of visited dirs incase of
+# recursion. Testing is now by inode, used to be by name.
+# 1.02 [KK 2006-06-01] 'findbin' searches for .exe too now, for Cygwin support
# 1.01 [KK 2005-09-29] Implemented context-sensitive help via -h.
# Action 'header' implemented.
# 1.00 [KK 2005-09-28] First version
@@ -111,11 +114,11 @@ sub uname() {
}
# Find a binary along the path.
-sub findbin ($) {
+sub findbin($) {
my $bin = shift;
msg ("Looking for executable '$bin'\n");
foreach my $d (split (/:/, $ENV{PATH})) {
- if (-x "$d/$bin") {
+ if (-x "$d/$bin" or -f "$d/bin.exe") {
msg ("Found as '$d/$bin'\n");
return ("$d/$bin");
}
@@ -129,12 +132,14 @@ sub subfiles ($$$) {
my ($dir, $mask, $recursive) = @_;
%_dir_visited = () unless ($recursive);
- if ($_dir_visited{$dir}) {
- msg ("Path '$dir' was already visited\n");
+ my ($dev, $ino) = stat($dir)
+ or return (undef);
+ my $tag = sprintf ("%d-%d", $dev, $ino);
+ if ($_dir_visited{$tag}) {
+ msg ("Path '$dir' was already visited (as $_dir_visited{$tag})\n");
return (undef);
}
- my ($dev, $ino) = stat($dir);
- $_dir_visited{$dir} = sprintf ("%d-%d", $dev, $ino);
+ $_dir_visited{$tag} = $dir;
msg ("Scanning for '$mask' under '$dir'\n");
if (! -d $dir) {
@@ -185,7 +190,7 @@ sub if_header {
When found, a define-flag for the C compiler is returned.
E.g.: $base ifheader malloc.h HAVE_MALLOC_H (may return -DHAVE_MALLOC_H)
Use in a Makefile as in:
-CFLAGS = $(CFLAGS) $(shell c-conf ifheader malloc.h HAVE_MALLOC_H
+CFLAGS = \$(CFLAGS) \$(shell c-conf ifheader malloc.h HAVE_MALLOC_H
Then in a C source as:
#ifdef HAVE_MALLOC_H
#include <malloc.h>
@@ -298,13 +303,13 @@ sub so_cflags {
building objects for a shared library.
E.g.: $base so-cflags (may return '-fPIC')
Use in a Makefile as in:
-CFLAGS = -c -g -Wall $(shell c-conf so-cflags)
+CFLAGS = -c -g -Wall \$(shell c-conf so-cflags)
ENDHELP
usage() if ($#_ > -1);
if (uname() eq 'Darwin') {
output ('-fPIC');
- } else {
+ } elsif (uname() eq 'Linux') {
output ('-fpic');
}
}
@@ -316,7 +321,7 @@ sub so_lflags {
combining objects into a shared library.
E.g.: $base so-lflags (may return '-dynamiclib -Wl,-single_module')
Use in a Makefile as in:
-MY_SO = \$(shell c-conf s-name my)
+MY_SO = \$(shell c-conf so-name my)
\$(MY_SO): *.o
\$(CC) -o \$(MY_SO) \$(shell c-conf so-lflags) *.o
ENDHELP