diff --git a/astksh_builtin_poll20120806_001.diff b/astksh_builtin_poll20120806_001.diff new file mode 100644 index 0000000..ce85185 --- /dev/null +++ b/astksh_builtin_poll20120806_001.diff @@ -0,0 +1,893 @@ +diff -N -r -u original/src/cmd/ksh93/bltins/poll.c build_poll/src/cmd/ksh93/bltins/poll.c +--- src/cmd/ksh93/bltins/poll.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/cmd/ksh93/bltins/poll.c 2012-08-07 05:13:40.057935800 +0200 +@@ -0,0 +1,717 @@ ++/*********************************************************************** ++* * ++* This software is part of the ast package * ++* Copyright (c) 2007-2012 AT&T Intellectual Property * ++* and is licensed under the * ++* Eclipse Public License, Version 1.0 * ++* by AT&T Intellectual Property * ++* * ++* A copy of the License is available at * ++* http://www.eclipse.org/org/documents/epl-v10.html * ++* (with md5 checksum b35adb5213ca9657e911e9befb180842) * ++* * ++* Information and Software Systems Research * ++* AT&T Research * ++* Florham Park NJ * ++* * ++* Roland Mainz * ++* * ++***********************************************************************/ ++#pragma prototyped ++ ++#include "defs.h" ++#include "variables.h" ++#include "lexstates.h" ++#include "io.h" ++#include "name.h" ++#include "builtins.h" ++#include "history.h" ++#include "terminal.h" ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef SH_DICT ++# define SH_DICT "libshell" ++#endif ++ ++#define sh_contexttoshell(context) ((context)?((context)->shp):(NULL)) ++ ++static ++const char sh_optpoll[] = ++"[-?\n@(#)$Id: poll (AT&T Labs Research) 2012-08-01 $\n]" ++"[-author?Roland Mainz ]" ++"[-license?http://www.eclipse.org/org/documents/epl-v10.html]" ++"[+NAME? poll - input/output multiplexing]" ++"[+DESCRIPTION?The poll command provides applications with a " ++ "mechanism for multiplexing input/output over a set of " ++ "file descriptors. " ++ "For each member of the (optionally sparse) indexed or " ++ "associative compound or type (see \btypeset -T\b) array " ++ "variable \bvar\b, poll examines the given file descriptor " ++ "in the subscript \b.fd\b for the event(s) specified in " ++ "the subscript \b.events\b. " ++ "The poll command identifies those file descriptors on " ++ "which an application can read or write data, or on which " ++ "certain events have occurred.]" ++"[+?The \bvar\b argument specifies an array of file descriptors to " ++ "be examined and the events of interest for each file " ++ "descriptor. " ++ "It is a array of compound variables (or user-defined type) " ++ "with one member for each open file descriptor of interest. " ++ "The array's compound or type variable members contain the " ++ "following subscripts:]{" ++ "[+?\b.fd\b # file descriptor]" ++ "[+?\b.events\b # compound variable of requested event(s)]" ++ "[+?\b.revents\b # compound variable of returned event(s)]" ++ "}" ++"[+?The \bfd\b variable specifies an open file descriptor and the " ++ "\bevents\b and \brevents\b members are compound variables " ++ "constructed from the following boolean member variables:]" ++ "{ " ++ "[+.pollin?('true'|'false') Data other than high priority " ++ "data may be read without blocking. For STREAMS, this " ++ "flag is set in \brevents\b even if the message " ++ "is of zero length.]" ++ "[+.pollrdnorm?('true'|'false') Normal data (priority band " ++ "equals 0) may be read without blocking. For STREAMS, " ++ "this flag is set in \brevents\b even if the message " ++ "is of zero length.]" ++ "[+.pollrdband?('true'|'false') Data from a non-zero " ++ "priority band may be read without blocking. For " ++ "STREAMS, this flag is set in \brevents\b even if the " ++ "message is of zero length.]" ++ "[+.pollpri?('true'|'false') High priority data may be " ++ "received without blocking. For STREAMS, this flag is " ++ "set in \brevents\b even if the message is of zero " ++ "length.]" ++ "[+.pollout?('true'|'false') Normal data (priority band " ++ "equals 0) may be written without blocking.]" ++ "[+.pollwrnorm?('true'|'false') The same as \bpollout\b.]" ++ "[+.pollwrband?('true'|'false') Priority data (priority band " ++ "> 0) may be written. This event only examines bands " ++ "that have been written to at least once.]" ++ "[+.pollerr?('true'|'false') An error has occurred on the " ++ "device or stream. This flag is only valid in the " ++ "\brevents\b compound variable; it is not used in the " ++ "\bevents\b compound variable.]" ++ "[+.pollhup?('true'|'false') A hangup has occurred on the " ++ "stream. This event and \bpollout\b are mutually " ++ "exclusive; a stream can never be writable if a " ++ "hangup has occurred. " ++ "However, this event and \bpollin\b, " ++ "\bpollrdband\b, or \bpollpri\b are not " ++ "mutually exclusive. This flag is only valid " ++ "in the \brevents\b compound variable; it is not " ++ "used in the \bevents\b compound variable.]" ++ "[+.pollnval?('true'|'false') The specified fd value does " ++ "not belong to an open file. " ++ "This flag is only valid in the \brevents\b compound " ++ "variable; it is not used in the \bevents\b " ++ "compound variable.]" ++ "}" ++"]" ++ ++"[+?If the value fd is less than 0, events is ignored and " ++ "revents is set to 0 in that entry on return from poll.]" ++ ++"[+?The results of the poll query are stored in the \brevents\b " ++ "compound variable members in the \bvar\b structure. " ++ "\bpoll*\b-variables are set in the \brevents\b compound " ++ "variable to indicate which of the requested events are true. " ++ "If none are true, the matching member in the \brevents\b " ++ "compound variable will have the value of 'false' when the " ++ "poll command returns. " ++ "The \brevents\b compound variable members \bpollhup\b, " ++ "\bpollerr\b, and \bpollnval\b are always set to 'true' in " ++ "\brevents\b if the conditions they indicate are true; this " ++ "occurs even though these flags were not present and/or set " ++ "to 'true' in the \bevents\b compound variable.]" ++ ++"[+?If none of the defined events have occurred on any selected " ++ "file descriptor, poll waits at least timeout milliseconds " ++ "for an event to occur on any of the selected file " ++ "descriptors. " ++ "On a computer where millisecond timing accuracy is not " ++ "available, timeout is rounded up to the nearest legal value " ++ "available on that system. If the value timeout is 0, poll " ++ "returns immediately. If the value of timeout is -1, poll " ++ "blocks until a requested event occurs or until the call is " ++ "interrupted.]" ++ ++"[+?The poll utility supports regular files, terminal and " ++ "pseudo-terminal devices, STREAMS-based files, FIFOs, and " ++ "pipes. The behavior of poll on elements of fds that refer " ++ "to other types of file is unspecified.]" ++ ++"[+?The poll utility supports sockets.]" ++#ifdef __SunOS ++"[+?The poll utility may be used on Solaris on directory fds of " ++ "/proc/$pid/ to get a \bpollhup='true'\b when the process quits.]" ++#endif ++"[+?A file descriptor for a socket that is listening for connections " ++ "will indicate that it is ready for reading, once connections " ++ "are available. A file descriptor for a socket that " ++ "is connecting asynchronously will indicate that it is ready " ++ "for writing, once a connection has been established.]" ++ ++"[+?Regular files always poll TRUE for reading and writing.]" ++ ++"[e:eventarray]:[fdcount?Upon successful completion, an indexed array " ++ "of strings is returned which contains a list of array " ++ "subscripts in the poll array which received events.]" ++"[S!:pollsfio?Look into sfio streams for buffered information and set " ++ "pollin/pollout to reflect sfio stream state.]" ++"[R:pollttyraw?Put tty connections into raw mode when polling. The " ++ "fd is returned to tty cooked mode before poll(1) exits.]" ++"[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, " ++ "poll returns immediately. If the value of timeout is -1, " ++ "poll blocks until a requested event occurs or until the " ++ "call is interrupted.]" ++"\n" ++"\nvar\n" ++"\n" ++"[+EXIT STATUS?]{" ++ "[+0?Success.]" ++ "[+>0?An error occurred.]" ++"}" ++"[+NOTES?]{" ++ "[+?poll*-variables defined in \bevents\b will always appear " ++ "in \brevents\b. This gives the script author control over " ++ "which poll*-variables he can expect in \brevents\b.]" ++ ++ "[+?The \bpollinhup\b, \bpollnval\b and \bpollerr\b variables " ++ "may appear in the \brevents\b compound variable even if " ++ "they were not requested in \bevents\b.]" ++ ++ "[+?Using the value of variables in \brevents\b which are " ++ "not set in \bevents\b can be done by putting a '-' suffix " ++ "after the variable name, e.g. use " ++ "\b${ar[x]].revents.pollhup-}\b to get the value of " ++ "\bar[x]].revents.pollhup\b or an empty string if the variable " ++ "was not set.]" ++ ++ "[+?Like \bpoll\b(2) it is legal to poll on the same fd in " ++ "multiple entries, for exanple to listen for different events " ++ "or to allow multiple callers to pool their poll lists " ++ "together into one \bpoll\b(1) call.]" ++"}" ++ ++/* quoting: ']' must be quoted as "]]" and '?' must be quoted as "//" */ ++"[+EXAMPLES?]{" ++ "[+?The following example will wait for 10 seconds for input " ++ "on fd 0, variable \bp[fd0]].revents.pollin\b will be 'true' " ++ "or 'false' depening on whether the stream 0 is ready for " ++ "reading:]{" ++ "[+?compound -A p=( [fd0]]=( fd=0 events=( pollin='true' ) ) ) ; poll -t10 p ; print -v p]" ++ "}" ++ ++ "[+?The following example will wait for 2 seconds for input " ++ "on fd 0, and variables \bp[0]].revents.pollin\b and " ++ "\bp[0]].revents.pollhup\b will be 'true' after polling ends " ++ "because there is both input data available and the end of " ++ "the stream was reached:]{" ++ "[+?printf '\\n' | ksh -c 'compound -a p=( ( fd=0 events=( pollin=\"true\" pollhup=\"true\" ) ) ) ; poll -t2 p ; print -v p']" ++ "}" ++"}" ++ ++"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]" ++; ++ ++ ++/* Like |nv_open()| but constructs variable name on the fly using |sprintf()| format */ ++static ++Namval_t *nv_open_fmt(Dt_t *dict, int flags, const char *namefmt, ...) ++{ ++ char varnamebuff[PATH_MAX]; ++ va_list ap; ++ ++ va_start(ap, namefmt); ++ vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap); ++ va_end(ap); ++ ++ return nv_open(varnamebuff, dict, flags); ++} ++ ++/* Name/value mapping table for POLL*-flags */ ++struct pollflagnamemap ++{ ++ const int flag; ++ const char *name; ++}; ++ ++const ++struct pollflagnamemap pfnm[]= ++{ ++ { POLLIN, "pollin" }, ++#ifdef POLLPRI ++ { POLLPRI, "pollpri" }, ++#endif ++ { POLLOUT, "pollout" }, ++#ifdef POLLRDNORM ++ { POLLRDNORM, "pollrdnorm" }, ++#endif ++#ifdef POLLWRNORM ++ { POLLWRNORM, "pollwrnorm" }, ++#endif ++#ifdef POLLRDBAND ++ { POLLRDBAND, "pollrdband" }, ++#endif ++#ifdef POLLWRBAND ++ { POLLWRBAND, "pollwrband" }, ++#endif ++#ifdef POLLMSG ++ { POLLMSG, "pollmsg" }, ++#endif ++#ifdef POLLREMOVE ++ { POLLREMOVE, "pollremove" }, ++#endif ++#ifdef POLLRDHUP ++ { POLLRDHUP, "pollrdhup" }, ++#endif ++ { POLLERR, "pollerr" }, ++ { POLLHUP, "pollhup" }, ++ { POLLNVAL, "pollnval" }, ++ { 0, NULL }, ++}; ++ ++/* structure to keep track of per array entry data */ ++struct pollstat ++{ ++ /* name of array subscript */ ++ const char *array_subscript; ++ ++ /* |sfio| keeps track of sfio information */ ++ struct ++ { ++ Sfio_t *sfd; ++ ssize_t flags; ++ } sfio; ++ ++ /* ++ * Bits in |eventvar_found| are POLL*-bits, set if matching ++ * ar[i].events.poll* var was found. We use this later to ++ * set the same ar[i].revents.poll* variable, regardless ++ * whether it was polled or not. This was done so the script ++ * author can control which poll* variables in the "revents" ++ * compound appear and which not. ++ */ ++ int eventvar_found; ++}; ++ ++/* poll on given |fds| data and retry after EINTR/EAGAIN while adjusting timeout */ ++static ++int poll_loop(Shbltin_t* context, struct pollfd *fds, nfds_t nfds, int timeout) ++{ ++/* nanoseconds to milliseconds */ ++#define TIME_NS2MS(t) ((t)/(1000UL*1000UL)) ++/* milliseconds to nanoseconds */ ++#define TIME_MS2NS(t) (((Time_t)(t))*(1000UL*1000UL)) ++ ++ int n; ++ ++ /* We need two codepaths here: ++ * 1. timeout > 0: we have to wait for |timeout| or events. ++ * 2. timeout <= 0: we have to wait forever (-1), return ++ * immediately (0) or an event occurs. ++ */ ++ if (timeout > 0) ++ { ++ const Time_t starttime = tmxgettime(); ++ Time_t timeout_ns = TIME_MS2NS(timeout); ++ ++ do ++ { ++ while(((n = poll(fds, nfds, timeout)) < 0) && ++ ((errno == EINTR) || (errno == EAGAIN)) && ++ (!context->sigset)) ++ errno=0; ++ ++ timeout_ns=timeout_ns-(tmxgettime()-starttime); ++ timeout=TIME_NS2MS(timeout_ns); ++ } while((timeout > 0) && (!context->sigset)); ++ } ++ else ++ { ++ while(((n = poll(fds, nfds, timeout)) < 0) && ++ ((errno == EINTR) || (errno == EAGAIN)) && ++ (!context->sigset)) ++ errno=0; ++ } ++ return n; ++} ++ ++/* set ".poll*"-variables in "ar[i].revents" per data in |currpollfd| and |currps| */ ++static ++void set_compound_revents(Shell_t *shp, const char *parrayname, struct pollstat *currps, struct pollfd *currpollfd) ++{ ++ const char *subname=currps->array_subscript; ++ Namval_t *np; ++ int pi; ++ ++ np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_COMVAR, "%s[%s].revents", parrayname, subname); ++ if (!np) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, "could not create pollfd %s[%s].revents", parrayname, subname); ++ return; ++ } ++ nv_setvtree(np); /* make "revents" really a compound variable */ ++ nv_close(np); ++ ++ for (pi=0 ; pfnm[pi].name != NULL ; pi++) ++ { ++ /* ++ * POLLHUP|POLLNVAL|POLLERR can always appear in |currpollfd->revents| ++ * even if we did not request them in |currpollfd->events| ++ */ ++ if ((currps->eventvar_found & pfnm[pi].flag) || ++ ((currpollfd->revents & (POLLHUP|POLLNVAL|POLLERR)) & pfnm[pi].flag)) ++ { ++ np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s[%s].revents.%s", parrayname, subname, pfnm[pi].name); ++ if (!np) ++ continue; ++ ++ nv_putval(np, ((currpollfd->revents & pfnm[pi].flag)?"true":"false"), 0); ++ nv_close(np); ++ } ++ } ++} ++ ++/* |main()| for poll(1) builtin */ ++extern ++int b_poll(int argc, char *argv[], Shbltin_t* context) ++{ ++ Shell_t *shp = sh_contexttoshell(context); ++ Namval_t *np, ++ *array_np, ++ *array_np_sub; ++ Sfio_t *strstk = NULL; /* stk object for memory allocations */ ++ const char *parrayname, /* name of array with poll data */ ++ *eventarrayname = NULL, /* name of array with indexes to results */ ++ *subname, /* current subscript */ ++ *s; ++ int n; ++ int fd; ++ nfds_t numpollfd = 0; /* number of entries to poll */ ++ int i, ++ j; ++ double timeout = -1.; ++ char buff[PATH_MAX*2+1]; /* fixme: theoretically enough to hold two variable names */ ++ bool ttyraw = false; ++ bool pollsfio = true; ++ int pi; /* index for |pfnm| */ ++ struct pollfd *pollfd = NULL, /* data for poll(2) */ ++ *currpollfd; /* current |pollfd| we are working on */ ++ struct pollstat *pollstat = NULL, /* context data from shell array */ ++ *currps; /* current |pollstat| we are working on */ ++ int retval = 0; /* return value of builtin */ ++ ++ while (n = optget(argv, sh_optpoll)) switch (n) ++ { ++ case 't': ++ errno = 0; ++ timeout = strtod(opt_info.arg, (char **)NULL); ++ if (errno != 0) ++ errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); ++ ++ /* -t uses seconds */ ++ if (timeout >=0) ++ timeout *= 1000.; ++ break; ++ case 'e': ++ eventarrayname = opt_info.arg; ++ break; ++ case 'S': ++ pollsfio=opt_info.num?true:false; ++ break; ++ case 'R': ++ ttyraw=opt_info.num?true:false; ++ break; ++ case ':': ++ errormsg(SH_DICT, ERROR_ERROR, "%s", opt_info.arg); ++ break; ++ case '?': ++ errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); ++ break; ++ } ++ argc -= opt_info.index; ++ argv += opt_info.index; ++ if(argc!=1) ++ errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); ++ ++ parrayname = argv[0]; ++ ++ strstk = stkopen(0); ++ if (!strstk) ++ errormsg(SH_DICT, ERROR_system(1), e_nospace); ++ ++ array_np = nv_open(parrayname, shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD); ++ if (!array_np) ++ { ++ stkclose(strstk); ++ errormsg(SH_DICT, ERROR_system(1), "cannot find array variable %s", parrayname); ++ } ++ if (!nv_isattr(array_np, NV_ARRAY)) ++ { ++ nv_close(array_np); ++ stkclose(strstk); ++ errormsg(SH_DICT, ERROR_system(1), "variable %s is not an array", parrayname); ++ } ++ ++ /* ++ * Count number of array elememts. We need to do it "manually" ++ * to handle sparse indexed and associative arrays ++ */ ++ nv_putsub(array_np, NULL, ARRAY_SCAN); ++ array_np_sub = array_np; ++ do ++ { ++ if (!(subname=nv_getsub(array_np_sub))) ++ break; ++ numpollfd++; ++ } while(array_np_sub && nv_nextsub(array_np_sub)); ++ ++ /* ++ * Done with counting, now we need to allocate a work area big enough ++ */ ++ pollfd = (struct pollfd *)stkalloc(strstk, (sizeof(struct pollfd) * numpollfd)); ++ pollstat = (struct pollstat *)stkalloc(strstk, (sizeof(struct pollstat) * numpollfd)); ++ if (!pollfd || !pollstat) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, e_nospace); ++ goto done_error; ++ } ++ ++ /* ++ * Walk the array again and fetch the data we need... ++ */ ++ nv_putsub(array_np, NULL, ARRAY_SCAN); ++ array_np_sub = array_np; ++ i = 0; ++ do ++ { ++ currps=&pollstat[i]; ++ currpollfd=&pollfd[i]; ++ ++ if (!(subname=nv_getsub(array_np_sub))) ++ break; ++ ++ currps->array_subscript=subname=stkcopy(strstk, subname); ++ if (!subname) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, e_nospace); ++ goto done_error; ++ } ++ ++ np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%s].fd", parrayname, subname); ++ if (!np) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, "missing pollfd %s[%s].fd", parrayname, subname); ++ goto done_error; ++ } ++ fd = (int)nv_getnum(np); ++ nv_close(np); ++ if ((fd < -1) || (fd > OPEN_MAX)) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, "invalid pollfd %s[%s].fd %d", parrayname, subname, fd); ++ goto done_error; ++ } ++ currpollfd->fd = fd; ++ ++ np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_COMVAR|NV_NOADD, "%s[%s].events", parrayname, subname); ++ if (!np) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, "missing pollfd %s[%s].events", parrayname, subname); ++ goto done_error; ++ } ++ nv_close(np); ++ ++ currpollfd->events=0; ++ currpollfd->revents=0; ++ currps->eventvar_found=0; ++ for (pi=0 ; pfnm[pi].name != NULL ; pi++) ++ { ++ const char *s; ++ ++ np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%s].events.%s", parrayname, subname, pfnm[pi].name); ++ if (!np) ++ continue; ++ ++ currps->eventvar_found |= pfnm[pi].flag; ++ s=nv_getval(np); ++ if ((s != NULL) && (!strcmp(s, "true"))) ++ currpollfd->events |= pfnm[pi].flag; ++ nv_close(np); ++ } ++ ++ i++; ++ } while(array_np_sub && nv_nextsub(array_np_sub)); ++ ++ nv_close(array_np); ++ array_np=NULL; ++ ++ /* ++ * If sfio handles fds we need to check whether there are ++ * any data in the sfio buffers and remember this information ++ * so we can set { POLLIN, POLLOUT } on demand to reflect ++ * this information. ++ */ ++ if (pollsfio) ++ { ++ Sfio_t **sfd; ++ int num_sfd=0, ++ active_sfd=0; ++ ++ sfd = (Sfio_t **)stkalloc(strstk, (sizeof(Sfio_t *) * (numpollfd+1))); ++ if (!sfd) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, e_nospace); ++ goto done_error; ++ } ++ ++ for (i=0 ; i < numpollfd ; i++) ++ { ++ currps=&pollstat[i]; ++ fd=pollfd[i].fd; ++ ++ currps->sfio.sfd=(fd>=0)?sh_fd2sfio(fd):NULL; ++ currps->sfio.flags=0; ++ if (currps->sfio.sfd!=NULL) ++ { ++ /* Only add |currps->sfio.sfd| to the ++ * |sfd| array (list of |Sfio_t*| ++ * passed to |sfpoll()|) if it is not ++ * in that list yet. This prevents ++ * that we call |sfpoll()| on the same ++ * sfio stream multiple times (which ++ * can happen if pollfd contains the ++ * same fd multiple times (which is ++ * valid usage, for example if multiple ++ * consumers pool their pool lists in ++ * one poll call or listen to different ++ * sets of poll event flags)). ++ */ ++ for (j=0 ; j < num_sfd ; j++) ++ { ++ if (sfd[j]==currps->sfio.sfd) ++ break; ++ } ++ if (j == num_sfd) ++ sfd[num_sfd++]=currps->sfio.sfd; ++ } ++ } ++ ++ active_sfd = sfpoll(&sfd[0], num_sfd, 0); ++ if (active_sfd > 0) ++ { ++ ssize_t sfpoll_flags; ++ ++ for (i=0 ; i < active_sfd ; i++) ++ { ++ sfpoll_flags=sfvalue(sfd[i]); ++ ++ /* ++ * We have to loop over all entries ++ * because single fd may be polled ++ * multiple times in different pollfd ++ * entries ++ */ ++ for (j=0 ; j < numpollfd ; j++) ++ { ++ if (pollstat[j].sfio.sfd == sfd[i]) ++ pollstat[j].sfio.flags=sfpoll_flags; ++ } ++ } ++ } ++ } ++ ++ /* ++ * Create --eventarray array on demand ++ */ ++ if (eventarrayname) ++ { ++ np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_ARRAY|NV_NOFAIL, "%s", eventarrayname); ++ if (!np) ++ { ++ errormsg(SH_DICT, ERROR_ERROR, "could not create eventarray variable %s", eventarrayname); ++ goto done_error; ++ } ++ ++ nv_close(np); ++ } ++ ++ /* ++ * Make sure we poll on "raw" tty to catch _every_ keystroke... ++ */ ++ if (ttyraw) ++ { ++ for (i=0 ; i < numpollfd ; i++) ++ { ++ fd=pollfd[i].fd; ++ if ((fd >=0) && (shp->fdstatus[fd]&IOTTY)) ++ tty_raw(fd, 1); ++ } ++ } ++ ++ /* ++ * ... then poll for events... ++ */ ++ n = poll_loop(context, pollfd, numpollfd, timeout); ++ ++ /* ++ * ... and restore the tty's to "cooked" mode ++ */ ++ if (ttyraw) ++ { ++ for (i=0 ; i < numpollfd ; i++) ++ { ++ fd=pollfd[i].fd; ++ if ((fd >=0) && (shp->fdstatus[fd]&IOTTY)) ++ tty_cooked(fd); ++ } ++ } ++ ++ if (n < 0) ++ { ++ /* |ERROR_system(0)| won't quit the builtin */ ++ errormsg(SH_DICT, ERROR_system(0), "poll(2) failure"); ++ retval=1; ++ } ++ ++ /* ++ * Write results back into the array ++ */ ++ for (i=0 ; i < numpollfd ; i++) ++ { ++ /* Adjust data in |pollfd[i]| to reflect sfio stream status (if requested) */ ++ if (pollsfio) ++ { ++ if ((pollfd[i].events & POLLIN) && (pollstat[i].sfio.flags & SF_READ)) ++ pollfd[i].revents |= POLLIN; ++ if ((pollfd[i].events & POLLOUT) && (pollstat[i].sfio.flags & SF_WRITE)) ++ pollfd[i].revents |= POLLOUT; ++ } ++ ++ set_compound_revents(shp, parrayname, &pollstat[i], &pollfd[i]); ++ ++ if (eventarrayname && pollfd[i].revents) ++ { ++ sprintf(buff, "%s+=( '%s' )", eventarrayname, pollstat[i].array_subscript); ++ sh_trap(buff, 0); ++ } ++ } ++ ++ goto done; ++ ++done_error: ++ retval=1; ++done: ++ if (array_np) ++ nv_close(array_np); ++ if (strstk) ++ stkclose(strstk); ++ ++ return(retval); ++} +diff -N -r -u original/src/cmd/ksh93/data/builtins.c build_poll/src/cmd/ksh93/data/builtins.c +--- src/cmd/ksh93/data/builtins.c 2012-06-19 10:02:12.000000000 +0200 ++++ src/cmd/ksh93/data/builtins.c 2012-08-06 23:25:47.431435123 +0200 +@@ -109,6 +109,7 @@ + #endif /* JOBS */ + "false", NV_BLTIN|BLT_ENV, bltin(false), + "getopts", NV_BLTIN|BLT_ENV, bltin(getopts), ++ "poll", NV_BLTIN, bltin(poll), + "print", NV_BLTIN|BLT_ENV, bltin(print), + "printf", NV_BLTIN|BLT_ENV, bltin(printf), + "pwd", NV_BLTIN, bltin(pwd), +diff -N -r -u original/src/cmd/ksh93/include/builtins.h build_poll/src/cmd/ksh93/include/builtins.h +--- src/cmd/ksh93/include/builtins.h 2012-01-10 20:11:54.000000000 +0100 ++++ src/cmd/ksh93/include/builtins.h 2012-08-06 23:25:47.432435170 +0200 +@@ -100,6 +100,7 @@ + extern int b_whence(int, char*[],Shbltin_t*); + + extern int b_alarm(int, char*[],Shbltin_t*); ++extern int b_poll(int, char*[],Shbltin_t*); + extern int b_print(int, char*[],Shbltin_t*); + extern int b_printf(int, char*[],Shbltin_t*); + extern int b_pwd(int, char*[],Shbltin_t*); +diff -N -r -u original/src/cmd/ksh93/Makefile build_poll/src/cmd/ksh93/Makefile +--- src/cmd/ksh93/Makefile 2012-06-19 09:46:54.000000000 +0200 ++++ src/cmd/ksh93/Makefile 2012-08-06 23:25:47.432435170 +0200 +@@ -161,6 +161,7 @@ + + shell$(RELEASE) $(VERSION) id=shell :LIBRARY: shell.3 nval.3 alarm.c cd_pwd.c cflow.c deparse.c \ + enum.c getopts.c hist.c misc.c print.c read.c sleep.c trap.c test.c \ ++ poll.c \ + typeset.c ulimit.c umask.c whence.c main.c nvdisc.c nvtype.c \ + arith.c args.c array.c completion.c defs.c edit.c expand.c regress.c \ + fault.c fcin.c history.c init.c io.c jobs.c lex.c macro.c name.c \ +diff -N -r -u original/src/cmd/ksh93/Mamfile build_poll/src/cmd/ksh93/Mamfile +--- src/cmd/ksh93/Mamfile 2012-07-27 18:05:35.000000000 +0200 ++++ src/cmd/ksh93/Mamfile 2012-08-06 23:25:47.432435170 +0200 +@@ -548,6 +548,22 @@ + prev bltins/test.c + exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} -D_API_ast=20100309 -D_PACKAGE_ast -D_BLD_shell -DSHOPT_DYNAMIC -DSHOPT_MULTIBYTE -DSHOPT_PFSH -DSHOPT_STATS -DSHOPT_NAMESPACE -DSHOPT_COSHELL -DSHOPT_HISTEXPAND -DERROR_CONTEXT_T=Error_context_t -DSHOPT_FIXEDARRAY -DSHOPT_ESH -DKSHELL -c bltins/test.c + done test.o generated ++ ++make poll.o ++make bltins/poll.c ++prev ${PACKAGE_ast_INCLUDE}/tmx.h implicit ++prev FEATURE/poll implicit ++prev FEATURE/externs implicit ++prev include/builtins.h implicit ++prev include/io.h implicit ++prev ${PACKAGE_ast_INCLUDE}/error.h implicit ++prev include/defs.h implicit ++done bltins/poll.c ++meta poll.o %.c>%.o bltins/poll.c test ++prev bltins/poll.c ++exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} -D_API_ast=20100309 -D_PACKAGE_ast -D_BLD_shell -DSHOPT_DYNAMIC -DSHOPT_MULTIBYTE -DSHOPT_PFSH -DSHOPT_STATS -DSHOPT_NAMESPACE -DSHOPT_COSHELL -DSHOPT_DYNAMIC -DSHOPT_HISTEXPAND -DERROR_CONTEXT_T=Error_context_t -DSHOPT_FIXEDARRAY -DSHOPT_ESH -DKSHELL -c bltins/poll.c ++done poll.o generated ++ + make typeset.o + make bltins/typeset.c + prev FEATURE/dynamic implicit +@@ -1328,7 +1344,7 @@ + prev edit/hexpand.c + exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} -DSHOPT_HISTEXPAND -DSHOPT_EDPREDICT -DSHOPT_MULTIBYTE -DKSHELL -DSHOPT_ESH -DSHOPT_VSH -D_PACKAGE_ast -DSHOPT_PFSH -DSHOPT_STATS -DSHOPT_NAMESPACE -DSHOPT_COSHELL -DSHOPT_DYNAMIC -D_BLD_shell -DERROR_CONTEXT_T=Error_context_t -D_API_ast=20100309 -DSHOPT_FIXEDARRAY -c edit/hexpand.c + done hexpand.o generated +-exec - ${AR} rc libshell.a alarm.o cd_pwd.o cflow.o deparse.o enum.o getopts.o hist.o misc.o print.o read.o sleep.o trap.o test.o typeset.o ulimit.o umask.o whence.o main.o nvdisc.o nvtype.o arith.o args.o array.o completion.o defs.o edit.o expand.o regress.o fault.o fcin.o ++exec - ${AR} rc libshell.a alarm.o cd_pwd.o cflow.o deparse.o enum.o getopts.o hist.o misc.o poll.o print.o read.o sleep.o trap.o test.o typeset.o ulimit.o umask.o whence.o main.o nvdisc.o nvtype.o arith.o args.o array.o completion.o defs.o edit.o expand.o regress.o fault.o fcin.o + exec - ${AR} rc libshell.a history.o init.o io.o jobs.o lex.o macro.o name.o nvtree.o parse.o path.o string.o streval.o subshell.o tdump.o timers.o trestore.o waitevent.o xec.o env.o limits.o msg.o strdata.o testops.o keywords.o options.o signals.o aliases.o builtins.o variables.o lexstates.o emacs.o vi.o hexpand.o + exec - (ranlib libshell.a) >/dev/null 2>&1 || true + done libshell.a generated +diff -N -r -u original/src/cmd/ksh93/tests/builtin_poll.sh build_poll/src/cmd/ksh93/tests/builtin_poll.sh +--- src/cmd/ksh93/tests/builtin_poll.sh 1970-01-01 01:00:00.000000000 +0100 ++++ src/cmd/ksh93/tests/builtin_poll.sh 2012-08-07 03:22:34.753348550 +0200 +@@ -0,0 +1,100 @@ ++######################################################################## ++# # ++# This software is part of the ast package # ++# Copyright (c) 2009-2012 Roland Mainz # ++# and is licensed under the # ++# Eclipse Public License, Version 1.0 # ++# by AT&T Intellectual Property # ++# # ++# A copy of the License is available at # ++# http://www.eclipse.org/org/documents/epl-v10.html # ++# (with md5 checksum b35adb5213ca9657e911e9befb180842) # ++# # ++# # ++# Roland Mainz # ++# # ++######################################################################## ++ ++# ++# Copyright (c) 2009, 2012, Roland Mainz. All rights reserved. ++# ++ ++# ++# Test module to check the ksh93 "poll" builtin ++# ++ ++# test setup ++function err_exit ++{ ++ print -u2 -n '\t' ++ print -u2 -r ${Command}[$1]: "${@:2}" ++ (( Errors++ )) ++} ++alias err_exit='err_exit $LINENO' ++ ++set -o nounset ++Command=${0##*/} ++integer Errors=0 ++ ++typeset ocwd ++typeset tmpdir ++ ++# create temporary test directory ++ocwd="${PWD}" ++tmpdir="${ mktemp -t -d 'test_builtin_poll.XXXXXXXX' ; }" || err_exit 'Cannot create temporary directory.' ++ ++cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors<125?Errors:125)) ; } ++ ++ ++# basic tests ++function test1 ++{ ++ compound d1=( ++ compound -A u=( ++ [y]=( integer fd=5 ; compound events=( pollin='true' ) revents=() ) ++ [x]=( integer fd=5 ; compound events=( pollin='true' ) revents=() ) ++ ) ++ ) ++ ++ # test 1: ++ print -C d1 >'testdata.cpv' ++ cat '/dev/zero' | $SHELL -o errexit -c 'builtin poll ; read -C <"testdata.cpv" d1 ; redirect 5<&0 ; poll -e d1.res -t 5. d1.u ; print -C d1 >"testdata.cpv"' >'log.txt' 2>&1 || err_exit "poll returned non-zero exit code $?" ++ unset d1 ; read -C d1 <'testdata.cpv' || err_exit 'Cannot read test data.' ++ [[ "$(< 'log.txt')" == '' ]] || err_exit "Excepted empty stdout/stderr, got $(printf '%q\n' "$(< 'log.txt')")" ++ [[ "${d1.u[x].revents.pollin-}" == 'true' ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents-}', not 'POLLIN'" ++ [[ "${d1.u[y].revents.pollin-}" == 'true' ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents-}', not 'POLLIN'" ++ [[ "${d1.res[*]-}" == 'x y' ]] || err_exit "d1.res contains '${d1.res[*]-}', not 'x y'" ++ ++ rm 'testdata.cpv' 'log.txt' ++ ++ # test 2: ++ unset d1.res ++ d1.u[z]=( integer fd=5 ; compound events=( pollout='true' ) revents=() ) ++ ++ print -C d1 >'testdata.cpv' ++ $SHELL -o errexit -c 'builtin poll ; read -C <"testdata.cpv" d1 ; { poll -e d1.res -t 5. d1.u ; } 5<"/dev/null" 5>"/dev/null" ; print -C d1 >"testdata.cpv"' >'log.txt' 2>&1 || err_exit "poll returned non-zero exit code $?" ++ unset d1 ; read -C d1 <'testdata.cpv' || err_exit 'Cannot read test data.' ++ ++ [[ "$(< 'log.txt')" == '' ]] || err_exit "Excepted empty stdout/stderr, got $(printf '%q\n' "$(< 'log.txt')")" ++ [[ "${d1.u[x].revents.pollin-}" == 'true' ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents-}', not 'POLLIN'" ++ [[ "${d1.u[y].revents.pollin-}" == 'true' ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents-}', not 'POLLIN'" ++ [[ "${d1.u[z].revents.pollout-}" == 'true' ]] || err_exit "d1.u[z].revents contains '${d1.u[z].revents-}', not 'POLLOUT,'" ++ [[ "${d1.res[*]-}" == 'x y z' ]] || err_exit "d1.res contains '${d1.res[*]-}', not 'x y z'" ++ ++ rm 'testdata.cpv' 'log.txt' ++ ++ return 0 ++} ++ ++# run tests ++builtin 'poll' || err_exit 'poll builtin not found.' ++ ++test1 ++ ++# cleanup ++cd "${ocwd}" ++rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}." ++ ++ ++# tests done ++exit $((Errors<125?Errors:125)) diff --git a/ksh.changes b/ksh.changes index 0379514..a45593a 100644 --- a/ksh.changes +++ b/ksh.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Sep 18 14:18:09 UTC 2012 - werner@suse.de + +- Add polling builtin patch (bnc #779888) + ------------------------------------------------------------------- Fri Jul 13 12:47:35 UTC 2012 - agraf@suse.com diff --git a/ksh.spec b/ksh.spec index 03ddddd..d3a0d7e 100644 --- a/ksh.spec +++ b/ksh.spec @@ -109,6 +109,7 @@ Patch23: ksh93-foreground-prgrp.dif Patch24: ksh93-builtin.dif Patch25: ksh93-vmleak.dif Patch26: ksh93-read-dont-ignore-esc.dif +Patch27: astksh_builtin_poll20120806_001.diff Patch42: ksh-locale.patch %description @@ -191,6 +192,7 @@ fi %patch24 %patch25 %patch26 +%patch27 %build #