# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <poll.h>
# include <stropts.h>
# include <fcntl.h>
# include <errno.h>
#include <syslog.h>
#include <user_attr.h>
#include <secdb.h>
#include <pwd.h>
# include "lp.h"
# include "msgs.h"
#define TURN_ON(X,F) (void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0)|(F)))
static int NumEvents = 0;
static int NumCons = 0;
static int ConsSize= 0;
static int NumNewCons = 0;
static MESG ** Connections = NULL;
static struct pollfd * PollFdList = NULL;
int
mlisteninit(MESG * md)
{
if (md == NULL)
{
errno = EINVAL;
return(-1);
}
if (ConsSize > 0)
{
errno = EBUSY;
return(-1);
}
ConsSize = 20;
Connections = (MESG **) Malloc(ConsSize * MDSIZE);
PollFdList = (struct pollfd*) Malloc(ConsSize * sizeof(struct pollfd));
if (Connections == NULL || PollFdList == NULL)
{
errno = ENOMEM;
return(-1);
}
Connections[0] = md;
PollFdList[0].fd = md->readfd;
PollFdList[0].events = POLLIN;
PollFdList[0].revents = 0;
NumCons = 1;
return(0);
}
int
mlistenadd(MESG * md, short events)
{
int slack;
struct pollfd * fdp;
slack = ConsSize - (NumCons + NumNewCons + 1);
if (slack < 0)
{
ConsSize += 20;
Connections = (MESG **) Realloc(Connections, ConsSize * MDSIZE);
PollFdList = (struct pollfd*) Realloc(PollFdList, ConsSize * sizeof(struct pollfd));
if (Connections == NULL || PollFdList == NULL)
{
errno = ENOMEM;
return(-1);
}
}
if (slack > 20)
{
ConsSize -= 20;
Connections = (MESG **) Realloc(Connections, ConsSize * MDSIZE);
PollFdList = (struct pollfd*) Realloc(PollFdList, ConsSize * sizeof(struct pollfd));
if (Connections == NULL || PollFdList == NULL)
{
errno = ENOMEM;
return(-1);
}
}
fdp = PollFdList + (NumCons + NumNewCons);
fdp->fd = md->readfd;
fdp->events = events;
fdp->revents = 0;
Connections[NumCons + NumNewCons++] = md;
return(0);
}
MESG *
mlistenreset ( void )
{
int x;
MESG * md;
if (ConsSize == 0)
return(NULL);
ConsSize = 0;
for (x = 1; x < NumCons; x++)
(void) mdisconnect(Connections[x]);
md = Connections[0];
Free(Connections);
Free(PollFdList);
Connections = NULL;
PollFdList = NULL;
NumCons = 0;
NumNewCons = 0;
NumEvents = 0;
return(md);
}
MESG *
mlisten()
{
extern uid_t Lp_Uid;
MESG * mdp;
MESG * md;
MQUE * p;
int flag = 0;
int disconacts;
int x;
int y;
struct pollfd * fdp;
struct strrecvfd recbuf;
#if defined(NOCONNLD)
struct strbuf ctl;
char cbuff[MSGMAX];
#endif
#if defined(NOCONNLD)
ctl.buf = cbuff;
ctl.maxlen = sizeof (cbuff);
#endif
for (;;)
{
if (NumEvents <= 0)
{
NumCons += NumNewCons;
NumNewCons = 0;
if (NumCons <= 0)
{
errno = EINTR;
return(NULL);
}
for (x = 0; x < NumCons; x++)
{
mdp = Connections[x];
if (mdp->readfd == -1)
{
disconacts = mdisconnect(mdp);
NumCons--;
for (y = x; y < (NumCons + NumNewCons); y++)
{
Connections[y] = Connections[y + 1];
PollFdList[y] = PollFdList[y + 1];
}
if (disconacts > 0)
{
errno = EINTR;
return(NULL);
}
else
x--;
} else {
PollFdList[x].events = POLLIN;
if (mdp->mque)
PollFdList[x].events |= POLLOUT;
}
}
if ((NumEvents = poll(PollFdList, NumCons, -1)) < 0)
{
errno = EAGAIN;
return(NULL);
}
}
for (x = 0; x < NumCons; x++)
{
mdp = Connections[x];
fdp = PollFdList + x;
if (fdp->revents == 0)
continue;
switch (mdp->type) {
case MD_MASTER:
if (fdp->revents != POLLIN)
{
errno = EINVAL;
return(NULL);
}
if (ioctl(mdp->readfd, I_RECVFD, &recbuf) != 0)
{
if (errno == EINTR)
{
errno = EAGAIN;
return(NULL);
}
if (errno == ENXIO)
{
fdp->revents = 0;
NumEvents--;
continue;
}
#if defined(NOCONNLD)
if (errno == EBADMSG)
while (Getmsg(mdp, &ctl, &ctl, &flag) >= 0);
#endif
return(NULL);
}
TURN_ON(recbuf.fd, O_NDELAY);
if ((md = (MESG *)Malloc(MDSIZE)) == NULL)
{
errno = ENOMEM;
return(NULL);
}
memset(md, 0, sizeof (MESG));
md->gid = recbuf.gid;
md->readfd = md->writefd = recbuf.fd;
md->state = MDS_IDLE;
md->type = MD_UNKNOWN;
md->uid = recbuf.uid;
md->admin = (md->uid == 0 || md->uid == Lp_Uid);
if (md->admin == 0) {
struct passwd *pw = NULL;
if ((pw = getpwuid(md->uid)) != NULL)
md->admin = chkauthattr("solaris.print.admin",
pw->pw_name);
}
get_peer_label(md->readfd, &md->slabel);
if (mlistenadd(md, POLLIN) != 0)
return(NULL);
ResetFifoBuffer (md->readfd);
fdp = PollFdList + x;
fdp->revents = 0;
NumEvents--;
break;
case MD_CHILD:
if (fdp->revents & POLLOUT) {
if (mdp->mque) {
if (mflush(mdp) < 0) {
syslog(LOG_DEBUG,
"MD_CHILD mflush failed");
}
}
}
if (fdp->revents & POLLIN) {
mdp->event = fdp->revents;
NumEvents--;
fdp->revents = 0;
return (mdp);
}
NumEvents--;
fdp->revents = 0;
break;
default:
if (fdp->revents & POLLNVAL)
{
if (mdp->readfd >= 0) {
Close (mdp->readfd);
if (mdp->writefd == mdp->readfd)
mdp->writefd = -1;
mdp->readfd = -1;
}
fdp->revents = 0;
NumEvents--;
continue;
}
if (fdp->revents & POLLERR)
{
if (mdp->readfd >= 0) {
Close (mdp->readfd);
if (mdp->writefd == mdp->readfd)
mdp->writefd = -1;
mdp->readfd = -1;
}
NumEvents--;
fdp->revents = 0;
continue;
}
if (fdp->revents & POLLHUP)
{
NumEvents--;
fdp->revents = 0;
if (mdp->readfd >= 0) {
Close (mdp->readfd);
if (mdp->writefd == mdp->readfd)
mdp->writefd = -1;
mdp->readfd = -1;
}
continue;
}
if (fdp->revents & POLLOUT)
{
if (mdp->mque == NULL)
{
NumEvents--;
fdp->revents = 0;
continue;
}
while (mdp->mque) {
if (Putmsg(mdp, NULL, mdp->mque->dat, 0))
break;
p = mdp->mque;
mdp->mque = p->next;
Free(p->dat->buf);
Free(p->dat);
Free(p);
}
NumEvents--;
fdp->revents = 0;
continue;
}
if (fdp->revents & POLLIN)
{
NumEvents--;
mdp->event = fdp->revents;
fdp->revents = 0;
if (mdp->type == MD_UNKNOWN)
mdp->type = MD_STREAM;
return(mdp);
}
break;
}
}
}
}
# define VOID_FUNC_PTR void (*)()
# define PTR_TO_VOID_FUNC_PTR void (**)()
int
mon_discon(MESG * md, void (*fn)())
{
int size = 2;
void (**fnp) ();
if (md->on_discon)
{
for (fnp = md->on_discon; *fnp; fnp++)
size++;
if ((md->on_discon = (PTR_TO_VOID_FUNC_PTR) Realloc (md->on_discon, size * sizeof(VOID_FUNC_PTR))) == NULL)
{
errno = ENOMEM;
return(-1);
}
}
else
if ((md->on_discon = (PTR_TO_VOID_FUNC_PTR) Malloc (size * sizeof(VOID_FUNC_PTR))) == NULL)
{
errno = ENOMEM;
return(-1);
}
size--;
md->on_discon[size] = NULL;
size--;
md->on_discon[size] = fn;
return(0);
}