Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3152607
expect.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
expect.c
View Options
/** @file
* Simple expect module for the STONITH library.
*/
#include "clusterautoconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <libintl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
# include <sched.h>
#endif
#include "expect.h"
#ifndef EOS
# define EOS '\0'
#endif
/*
* Just incase we are on an out of date system
*/
#ifndef CLOCKS_PER_SEC
# ifndef CLK_TCK
# error Neither CLOCKS_PER_SEC nor CLK_TCK (obsolete) are defined
# endif /* CLK_TCK */
# define CLOCKS_PER_SEC CLK_TCK
#endif /* CLOCKS_PER_SEC */
void close_all_files (void);
/**
* Look for ('expect') any of a series of tokens in the input
* Return the token type for the given token or -1 on error.
*
* @param fd The file descriptor to watch.
* @param toklist The series of tokens to look for.
* @param to_secs Timeout (in seconds).
* @param buf Receive buffer (preallocated).
* @param maxline Length of receive buffer.
*/
int
ExpectToken(int fd, struct Etoken * toklist, int to_secs, char * buf
, int maxline)
{
clock_t starttime;
clock_t endtime;
int wraparound=0;
int tickstousec = (1000000/CLOCKS_PER_SEC);
clock_t now;
clock_t ticks;
int nchars = 1; /* reserve space for an EOS */
struct timeval tv;
struct tms tms_unused; /*This tms is unused, but cygwin doesn't like NULL in times*/
struct Etoken * this;
/* Figure out when to give up. Handle lbolt wraparound */
if (fd < 0) {
errno = EINVAL;
return -1;
}
starttime = times(&tms_unused);
ticks = (to_secs*CLOCKS_PER_SEC);
endtime = starttime + ticks;
if (endtime < starttime) {
wraparound = 1;
}
if (buf) {
*buf = EOS;
}
for (this=toklist; this->string; ++this) {
this->matchto = 0;
}
while (now = times(&tms_unused),
(wraparound && (now > starttime || now <= endtime))
|| (!wraparound && now <= endtime)) {
fd_set infds;
char ch;
clock_t timeleft;
int retval;
timeleft = endtime - now;
tv.tv_sec = timeleft / CLOCKS_PER_SEC;
tv.tv_usec = (timeleft % CLOCKS_PER_SEC) * tickstousec;
if (tv.tv_sec == 0 && tv.tv_usec < tickstousec) {
/* Give 'em a little chance */
tv.tv_usec = tickstousec;
}
/* Watch our FD to see when it has input. */
FD_ZERO(&infds);
FD_SET(fd, &infds);
retval = select(fd+1, &infds, NULL, NULL, &tv);
if (retval <= 0) {
errno = ETIMEDOUT;
return(-1);
}
/* Whew! All that work just to read one character! */
if (read(fd, &ch, sizeof(ch)) <= 0) {
return(-1);
}
/* Save the text, if we can */
if (buf && nchars < maxline-1) {
*buf = ch;
++buf;
*buf = EOS;
++nchars;
}
#if 0
fprintf(stderr, "%c", ch);
#endif
/* See how this character matches our expect strings */
for (this=toklist; this->string; ++this) {
if (ch == this->string[this->matchto]) {
/* It matches the current token */
++this->matchto;
if (this->string[this->matchto] == EOS){
/* Hallelujah! We matched */
return(this->toktype);
}
}else{
/* It doesn't appear to match this token */
int curlen;
int nomatch=1;
/*
* If we already had a match (matchto is
* greater than zero), we look for a match
* of the tail of the pattern matched so far
* (with the current character) against the
* head of the pattern.
*/
/*
* This is to make the string "aab" match
* the pattern "ab" correctly
* Painful, but nice to do it right.
*/
for (curlen = (this->matchto)
; nomatch && curlen >= 0
; --curlen) {
const char * tail;
tail=(this->string)
+ this->matchto
- curlen;
if (strncmp(this->string, tail
, curlen) == 0
&& this->string[curlen] == ch) {
if (this->string[curlen+1]==EOS){
/* We matched! */
/* (can't happen?) */
return(this->toktype);
}
this->matchto = curlen+1;
nomatch=0;
}
}
if (nomatch) {
this->matchto = 0;
}
}
}
}
errno = ETIMEDOUT;
return(-1);
}
/**
* Start a process with its stdin and stdout redirected to pipes
* so the parent process can talk to it.
*
* @param cmd Command line to run.
* @param readfd Filled with a pipe to the the output of the
* new child.
* @param writefd Filled with a pipe to the input of the new
* child.
* @param redir_err 0, 1 = stderr, 2 = setsid, 3 = both
* @return -1 on failure (with errno set appropriately) or
* or the PID of the new child process.
*/
int
StartProcess(const char * cmd, int * readfd, int * writefd, int flags)
{
pid_t pid;
int wrpipe[2]; /* The pipe the parent process writes to */
/* (which the child process reads from) */
int rdpipe[2]; /* The pipe the parent process reads from */
/* (which the child process writes to) */
if (pipe(wrpipe) < 0) {
perror("cannot create pipe\n");
return(-1);
}
if (pipe(rdpipe) < 0) {
perror("cannot create pipe\n");
close(wrpipe[0]);
close(wrpipe[1]);
return(-1);
}
switch(pid=fork()) {
case -1:
perror("cannot StartProcess cmd");
close(rdpipe[0]);
close(rdpipe[1]);
close(wrpipe[0]);
close(wrpipe[1]);
return(-1);
case 0:
/* We are the child */
/* Redirect stdin */
if (wrpipe[0] != 0) {
close(0);
if(dup2(wrpipe[0], 0) < 0) {
syslog(LOG_CRIT,
"StartProcess: dup2(%d,0) failed: %s\n",
wrpipe[0],
strerror(errno));
exit(1);
}
close(wrpipe[0]);
}
close(wrpipe[1]);
/* Redirect stdout */
if (rdpipe[1] != 1) {
close(1);
if(dup2(rdpipe[1], 1) < 0) {
syslog(LOG_CRIT,
"StartProcess: dup2(%d,1) failed: %s\n",
rdpipe[1],
strerror(errno));
exit(1);
}
close(rdpipe[1]);
}
close(rdpipe[0]);
if (flags & EXP_STDERR) {
/* Redirect stderr */
close(2);
if(dup2(1, 2) < 0) {
syslog(LOG_CRIT,
"StartProcess: dup2(1,2) failed: %s\n",
strerror(errno));
exit(1);
}
}
if (flags & EXP_NOCTTY)
setsid();
close_all_files(); /* Workaround telnet bugs */
#if defined(SCHED_OTHER)
{
/*
* Try and (re)set our scheduling to "normal"
* Sometimes our callers run in soft
* real-time mode. The program we exec might
* not be very well behaved - this is bad for
* operation in high-priority (soft real-time)
* mode. In particular, telnet is prone to
* going into infinite loops when killed.
*/
struct sched_param sp;
memset(&sp, 0, sizeof(sp));
sp.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &sp);
}
#endif
execlp("/bin/bash", "bash", "-c", cmd, NULL);
perror("cannot exec shell!");
exit(1);
default: /* We are the parent */
*readfd = rdpipe[0];
close(rdpipe[1]);
*writefd = wrpipe[1];
close(wrpipe[0]);
return(pid);
}
/*NOTREACHED*/
return(-1);
}
/**
* Close all file descriptors in a child process.
*
* Open fd's are inherited across exec unless they are
* marked close on exec, which must be done explicitly
* with fcntl(). While this should not affect the operation of
* telnet, it was found that in some cases it did. Its easier to
* just fix it this way than to fix telnet.
*/
void
close_all_files (void)
{
register int i, fd_table_size;
fd_table_size = getdtablesize ();
if (fd_table_size > 256)/* clamp to a reasonable value */
fd_table_size = 256;
for (i = 3; i < fd_table_size; i++)
close (i);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Feb 25, 12:51 AM (19 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1456922
Default Alt Text
expect.c (7 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment