V10/ipc/libipc/ipccreat.c

Compare this file to the similar file:
Show the results in this format:

#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;
}