V10/ipc/libipc/ipccreat.c
#include <sys/types.h>
#include <sys/filio.h>
#include <ipc.h>
#include "defs.h"
/* imports */
extern int conn_ld;
extern struct passwd *pwsearch();
extern char *strncpy();
/* global to this file */
#define ROOTUID 0
/*
* Attach to a name space. If the path is a single element,
* just mount into the file system. Otherwise, pass the request
* to a network dialer.
*/
int
ipccreat(name, param)
char *name; /* name being dialed */
char *param; /* parameters for creation */
{
int pfd[2];
char *path=name;
ipcinfo info;
int nfd;
if (path==NULL)
return ABORT(EINVAL, "name too long", (ipcinfo*)NULL);
/*
* if a path is specified, pass the request through a dialer
*/
if (strchr(path, '!')!=NULL) {
info.rfd = info.cfd = -1;
info.myname = info.user = info.machine = NULL;
info.uid = info.gid = -1;
info.name = name;
info.param = param;
info.flags = IPC_CREAT;
return ipcdial(&info);
}
/*
* Try creating a file to mount on
*/
if(access(path, 0) < 0){
nfd = creat(path, 0666);
if(nfd < 0)
return ABORT(errno, "can't mount", (ipcinfo*)NULL);
close(nfd);
}
/*
* make a pipe to mount into the file system and push the
* connection line discipline. Conn_ld ensures that all
* opens of the pipe will spawn a unique connection.
*/
if (pipe(pfd) < 0)
return ABORT(errno, "out of pipes", (ipcinfo*)NULL);
if (ioctl(pfd[1], FIOPUSHLD, &conn_ld) < 0) {
close(pfd[0]);
close(pfd[1]);
return ABORT(errno, "pushing line discipline", (ipcinfo*)NULL);
}
/* mount */
if (fmount(3, pfd[1], path, 0) < 0) {
close(pfd[0]);
close(pfd[1]);
return ABORT(errno, "can't mount", (ipcinfo*)NULL);
}
close(pfd[1]);
return pfd[0];
}
/*
* listen for a connection
*/
ipcinfo *
ipclisten(fd)
int fd;
{
struct passfd pass;
int pfd[2];
static ipcinfo info;
static char user[32];
int fd1=-1, fd2=-1;
/*
* Get a unique stream to a caller, or reuse this one if none is passed.
* The reuse is typical of the arpa! gateway.
*/
if(_fd_read(fd, &pass) < 0) {
if(errno==EINTR)
return NULL;
info.uid = -1;
info.gid = -1;
info.rfd = dup(fd);
close(fd);
} else {
info.uid = pass.uid;
info.gid = pass.gid;
info.rfd = pass.fd;
}
strncpy(user, pass.logname, sizeof(pass.logname));
user[sizeof(pass.logname)] = '\0';
info.user = user;
(void)ioctl(info.rfd, FIOACCEPT, &pass);
/*
* Get possible passed fds. Up to two can be passed, i.e.
* the fd to reply to and the one to use for communication.
*/
if (_fd_read(info.rfd, &pass)>=0) {
fd1 = pass.fd;
if (_fd_read(info.rfd, &pass)>=0) {
fd2 = pass.fd;
} else if(errno==EINTR){
close(info.rfd);
close(fd1);
return NULL;
}
} else if(errno==EINTR){
close(info.rfd);
return NULL;
}
/*
* get the request
*/
if (_info_read(info.rfd, &info)<0) {
/* requestor gave up */
close(info.rfd);
if(fd1>=0)
close(fd1);
if(fd2>=0)
close(fd2);
return NULL;
}
if (info.flags & IPC_HANDOFF) {
/*
* This is a call passed to us
* by someone else.
*/
close(info.rfd);
info.rfd = fd1;
info.cfd = fd2;
info.flags &= ~IPC_HANDOFF;
} else {
/*
* By default the fd on which the
* request was received will be used
* both for replies and communication
*/
info.cfd = fd1;
if (fd2>=0)
close(fd2);
}
return &info;
}
/*
* Accept a connection.
* Close all fd's except ip->cfd.
*/
int
ipcaccept(ip)
ipcinfo *ip;
{
return ipcdaccept(ip, -1, "who_cares");
}
/*
* Accept a connection, and supply a source address and communications fd
*/
int
ipcdaccept(ip, commfd, source)
ipcinfo *ip;
int commfd;
char *source;
{
if (commfd >= 0) {
/*
* supply our own channel for communications
*/
if (_fd_write(ip->rfd, commfd) < 0) {
close(commfd);
return ABORT(errno, "can't pass conection", ip);
}
_reply_write(ip->rfd, 0, source);
ABORT(0, "", ip);
ip->cfd = commfd;
} else if (ip->cfd >= 0) {
/*
* use client supplied channel for communications
*/
_reply_write(ip->rfd, 0, "");
close(ip->rfd);
ip->rfd = -1;
} else {
/*
* use reply channel for communications
*/
_reply_write(ip->rfd, 0, "");
ip->cfd = ip->rfd;
ip->rfd = -1;
}
return(ip->cfd);
}
/*
* Reject a connection.
*/
int
ipcreject(ip, no, str)
ipcinfo *ip;
int no; /* error number */
char *str; /* error string */
{
_reply_write(ip->rfd, no, str);
ABORT(no, str, ip);
return 0;
}