summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorthomas <thomas@FreeBSD.org>2006-08-16 12:58:41 +0000
committerthomas <thomas@FreeBSD.org>2006-08-16 12:58:41 +0000
commitbabdb5cd99b2260e12d4ed4018d86159fbf9e6ed (patch)
tree5c669036c1d5fcd2610038740f9b56bcb9399723 /usr.sbin
parentd020b899e458856a08d6608aac8e913aff9d1902 (diff)
downloadFreeBSD-src-babdb5cd99b2260e12d4ed4018d86159fbf9e6ed.zip
FreeBSD-src-babdb5cd99b2260e12d4ed4018d86159fbf9e6ed.tar.gz
Remove unsafe use of asynchronous I/O (the SIGIO handler could cause
incorrect reentrant calls to the libc memory manager). Add missing error handling: * for an incoming response with an incorrect tid; * for a failure to register the response RPC program, Fix error handling for failure to malloc job descriptor (this needs to be done before the transient RPC program is registered). PR: bin/102143 MFC after: 2 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/yppush/yppush_main.c164
1 files changed, 46 insertions, 118 deletions
diff --git a/usr.sbin/yppush/yppush_main.c b/usr.sbin/yppush/yppush_main.c
index 59108db..ceb63bc 100644
--- a/usr.sbin/yppush/yppush_main.c
+++ b/usr.sbin/yppush/yppush_main.c
@@ -65,14 +65,12 @@ int skip_master = 0; /* Do not attempt to push map to master. */
int verbose = 0; /* Toggle verbose mode. */
unsigned long yppush_transid = 0;
int yppush_timeout = 80; /* Default timeout. */
-int yppush_jobs = 0; /* Number of allowed concurrent jobs. */
+int yppush_jobs = 1; /* Number of allowed concurrent jobs. */
int yppush_running_jobs = 0; /* Number of currently running jobs. */
-int yppush_alarm_tripped = 0;
/* Structure for holding information about a running job. */
struct jobs {
unsigned long tid;
- int sock;
int port;
ypxfrstat stat;
unsigned long prognum;
@@ -84,6 +82,8 @@ struct jobs {
struct jobs *yppush_joblist; /* Linked list of running jobs. */
+static int yppush_svc_run(int);
+
/*
* Local error messages.
*/
@@ -114,19 +114,29 @@ yppush_show_status(ypxfrstat status, unsigned long tid)
job = yppush_joblist;
- while (job) {
+ while (job != NULL) {
if (job->tid == tid)
break;
job = job->next;
}
+ if (job == NULL) {
+ yp_error("warning: received callback with invalid transaction ID: %lu",
+ tid);
+ return (0);
+ }
+
if (job->polled) {
- return(0);
+ yp_error("warning: received callback with duplicate transaction ID: %lu",
+ tid);
+ return (0);
}
- if (verbose > 1)
+ if (verbose > 1) {
yp_error("checking return status: transaction ID: %lu",
job->tid);
+ }
+
if (status != YPPUSH_SUCC || verbose) {
yp_error("transfer of map %s to server %s %s",
job->map, job->server, status == YPPUSH_SUCC ?
@@ -173,11 +183,7 @@ yppush_exit(int now)
yp_error("%d transfer%sstill pending",
still_pending,
still_pending > 1 ? "s " : " ");
- yppush_alarm_tripped = 0;
- alarm(YPPUSH_RESPONSE_TIMEOUT);
- pause();
- alarm(0);
- if (yppush_alarm_tripped == 1) {
+ if (yppush_svc_run (YPPUSH_RESPONSE_TIMEOUT) == 0) {
yp_error("timed out");
now = 1;
}
@@ -209,42 +215,31 @@ to %s (transid = %lu) still pending", jptr->server, jptr->tid);
static void
handler(int sig)
{
- if (sig == SIGTERM || sig == SIGINT || sig == SIGABRT) {
- yppush_joblist = NULL;
- yppush_exit(1);
- }
-
- if (sig == SIGALRM) {
- alarm(0);
- yppush_alarm_tripped++;
- }
-
+ yppush_exit (1);
return;
}
/*
* Dispatch loop for callback RPC services.
+ * Return value:
+ * -1 error
+ * 0 timeout
+ * >0 request serviced
*/
-static void
-yppush_svc_run(void)
+static int
+yppush_svc_run(int timeout_secs)
{
-#ifdef FD_SETSIZE
+ int rc;
fd_set readfds;
-#else
- int readfds;
-#endif /* def FD_SETSIZE */
struct timeval timeout;
timeout.tv_usec = 0;
- timeout.tv_sec = 5;
+ timeout.tv_sec = timeout_secs;
retry:
-#ifdef FD_SETSIZE
readfds = svc_fdset;
-#else
- readfds = svc_fds;
-#endif /* def FD_SETSIZE */
- switch (select(_rpc_dtablesize(), &readfds, NULL, NULL, &timeout)) {
+ rc = select(svc_maxfd + 1, &readfds, NULL, NULL, &timeout);
+ switch (rc) {
case -1:
if (errno == EINTR)
goto retry;
@@ -257,25 +252,7 @@ retry:
svc_getreqset(&readfds);
break;
}
- return;
-}
-
-/*
- * Special handler for asynchronous socket I/O. We mark the
- * sockets of the callback handlers as O_ASYNC and handle SIGIO
- * events here, which will occur when the callback handler has
- * something interesting to tell us.
- */
-static void
-async_handler(int sig)
-{
- yppush_svc_run();
-
- /* reset any pending alarms. */
- alarm(0);
- yppush_alarm_tripped++;
- kill(getpid(), SIGALRM);
- return;
+ return rc;
}
/*
@@ -396,9 +373,17 @@ yp_push(char *server, char *map, unsigned long tid)
SVCXPRT *xprt;
struct jobs *job;
+ /* Register the job in our linked list of jobs. */
+
+ /* First allocate job structure */
+ if ((job = (struct jobs *)malloc(sizeof (struct jobs))) == NULL) {
+ yp_error("malloc failed");
+ yppush_exit (1);
+ }
+
/*
- * Register the callback service on the first free
- * transient program number.
+ * Register the callback service on the first free transient
+ * program number.
*/
xprt = svcudp_create(sock);
for (prognum = 0x40000000; prognum < 0x5FFFFFFF; prognum++) {
@@ -406,18 +391,15 @@ yp_push(char *server, char *map, unsigned long tid)
yppush_xfrrespprog_1, IPPROTO_UDP) == TRUE)
break;
}
-
- /* Register the job in our linked list of jobs. */
- if ((job = (struct jobs *)malloc(sizeof (struct jobs))) == NULL) {
- yp_error("malloc failed");
- yppush_exit(1);
+ if (prognum == 0x5FFFFFFF) {
+ yp_error ("can't register yppush_xfrrespprog_1");
+ yppush_exit (1);
}
/* Initialize the info for this job. */
job->stat = 0;
job->tid = tid;
job->port = xprt->xp_port;
- job->sock = xprt->xp_fd; /*XXX: Evil!! EEEEEEEVIL!!! */
job->server = strdup(server);
job->map = strdup(map);
job->prognum = prognum;
@@ -425,27 +407,6 @@ yp_push(char *server, char *map, unsigned long tid)
job->next = yppush_joblist;
yppush_joblist = job;
- /*
- * Set the RPC sockets to asynchronous mode. This will
- * cause the system to smack us with a SIGIO when an RPC
- * callback is delivered. This in turn allows us to handle
- * the callback even though we may be in the middle of doing
- * something else at the time.
- *
- * XXX This is a horrible thing to do for two reasons,
- * both of which have to do with portability:
- * 1) We really ought not to be sticking our grubby mits
- * into the RPC service transport handle like this.
- * 2) Even in this day and age, there are still some *NIXes
- * that don't support async socket I/O.
- */
- if (fcntl(xprt->xp_fd, F_SETOWN, getpid()) == -1 ||
- fcntl(xprt->xp_fd, F_SETFL, O_ASYNC) == -1) {
- yp_error("failed to set async I/O mode: %s",
- strerror(errno));
- yppush_exit(1);
- }
-
if (verbose) {
yp_error("initiating transfer: %s -> %s (transid = %lu)",
yppush_mapname, server, tid);
@@ -453,7 +414,7 @@ yp_push(char *server, char *map, unsigned long tid)
/*
* Send the XFR request to ypserv. We don't have to wait for
- * a response here since we can handle them asynchronously.
+ * a response here since we handle them asynchronously.
*/
if (yppush_send_xfr(job)){
@@ -486,27 +447,12 @@ yppush_foreach(int status, char *key, int keylen, char *val, int vallen,
return (0);
/*
- * Restrict the number of concurrent jobs. If yppush_jobs number
+ * Restrict the number of concurrent jobs: if yppush_jobs number
* of jobs have already been dispatched and are still pending,
* wait for one of them to finish so we can reuse its slot.
*/
- if (yppush_jobs <= 1) {
- yppush_alarm_tripped = 0;
- while (!yppush_alarm_tripped && yppush_running_jobs) {
- alarm(yppush_timeout);
- yppush_alarm_tripped = 0;
- pause();
- alarm(0);
- }
- } else {
- yppush_alarm_tripped = 0;
- while (!yppush_alarm_tripped && yppush_running_jobs >= yppush_jobs) {
- alarm(yppush_timeout);
- yppush_alarm_tripped = 0;
- pause();
- alarm(0);
- }
- }
+ while (yppush_running_jobs >= yppush_jobs && (yppush_svc_run (yppush_timeout) > 0))
+ ;
/* Cleared for takeoff: set everything in motion. */
if (yp_push(server, yppush_mapname, yppush_transid))
@@ -638,26 +584,8 @@ main(int argc, char *argv[])
yppush_master[data.size] = '\0';
/* Install some handy handlers. */
- signal(SIGALRM, handler);
signal(SIGTERM, handler);
signal(SIGINT, handler);
- signal(SIGABRT, handler);
-
- /*
- * Set up the SIGIO handler. Make sure that some of the
- * other signals are blocked while the handler is running so
- * select() doesn't get interrupted.
- */
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGIO); /* Goes without saying. */
- sigaddset(&sa.sa_mask, SIGPIPE);
- sigaddset(&sa.sa_mask, SIGCHLD);
- sigaddset(&sa.sa_mask, SIGALRM);
- sigaddset(&sa.sa_mask, SIGINT);
- sa.sa_handler = async_handler;
- sa.sa_flags = 0;
-
- sigaction(SIGIO, &sa, NULL);
/* set initial transaction ID */
yppush_transid = time((time_t *)NULL);
OpenPOWER on IntegriCloud