1
0
Files
2022-09-29 17:59:04 +03:00

943 lines
18 KiB
C

#ident "irix/cmd/mkpd.c: $Revision: 1.17 $"
#define SN0 1
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/conf.h>
#include <fcntl.h>
#include <sys/syssgi.h>
#include <syslog.h>
#include <sys/errno.h>
#include <sys/SN/router.h>
#include <sys/SN/SN0/sn0drv.h>
#include "mkpart.h"
#include "mkpd.h"
#include "mkprou.h"
extern int errno ;
static int debug ;
static int lock ;
#define DPRINT(l,x) if (debug >= l) printf x
#define SLEEP_AND_CONTINUE { sleep(MKPD_SLEEP_TIME) ; continue ; }
static void mkpd_prreq_ipaddr(mkpd_packet_t *, char *, int, int *) ;
static void mkpd_prreq_roucfg(mkpd_packet_t *, char *, int, int *) ;
static void mkpd_prreq_lock(mkpd_packet_t *, char *, int, int *) ;
static void mkpd_prreq_unlock(mkpd_packet_t *, char *, int, int *) ;
static int mkpd_lsock_init(void) ;
static void pr_loc_req(pfdi_t *, int) ;
static int get_data_from_remote(char, pfdi_t *, int, char *, int, int) ;
static void mkpd_close_part_raw(pfdi_t *pfdi, fd_set *fds) ;
static int is_mkpd_running(void) ;
/*
* Call back routines for remote requests to daemon.
*/
struct req_handler {
unsigned char reqid ;
void (*funcp)(mkpd_packet_t *, char *, int, int *) ;
} reqh[] = {
OPCODE_GET_IPADDR, mkpd_prreq_ipaddr,
OPCODE_GET_ROUCFG, mkpd_prreq_roucfg,
OPCODE_LOCK_PART, mkpd_prreq_lock,
OPCODE_UNLOCK_PART, mkpd_prreq_unlock,
0, NULL
} ;
void
init_timeval(struct timeval *t)
{
t->tv_sec = MKPD_SLEEP_TIME ;
t->tv_usec = 0 ;
}
/*
* pfdi - partition file descriptor info
* pfdi support
*/
int
pfdiLookup(pfdi_t *pfdi, partid_t p)
{
int i ;
for (i=0; i<pfdiCnt(pfdi); i++)
if (pfdiPartId(pfdi, i) == p)
return i ;
return -1 ;
}
int
pfdiDelete(pfdi_t *pfdi)
{
int i ;
for (i=0; i<pfdiCnt(pfdi); i++)
if (pfdiPartPi(pfdi, i))
free(pfdiPartPi(pfdi, i)) ;
return 1 ;
}
/*
* Add a partition to pfdi. Copy partinfo obtained from syssgi.
*/
int
pfdiAdd(pfdi_t *pfdi, part_info_t *pi)
{
int newi ;
newi = pfdiCnt(pfdi) ;
if ((pfdiPartPi(pfdi, newi) = (part_info_t *)
malloc(sizeof(part_info_t))) == NULL) {
return -1 ;
}
bcopy(pi, pfdiPartPi(pfdi, newi), sizeof(part_info_t)) ;
pfdiPartFd(pfdi, newi) = -1 ;
pfdiPartSts(pfdi, newi) = PFD_CLSE ;
pfdiCntIncr(pfdi) ;
return newi ;
}
void
pfdiDump(pfdi_t *pfdi)
{
int i ;
for (i=0; i<pfdiCnt(pfdi);i++)
printf("p = %d, fd = %d\n",
pfdiPartId(pfdi,i), pfdiPartFd(pfdi,i)) ;
}
void
pfdiFree(pfdi_t *pfdi)
{
pfdiDelete(pfdi) ;
if (pfdi)
free(pfdi) ;
}
pfdi_t *
pfdiInit(void)
{
pfdi_t *pf ;
pf = (pfdi_t *)malloc(sizeof(pfdi_t)) ;
if (pf == NULL)
goto init_done ;
bzero(pf, sizeof(pfdi_t)) ;
pfdiSize(pf) = MAX_PARTITIONS ;
init_done:
return pf ;
}
/*
* Build a request packet.
*/
void
mkpd_make_req( char ptype,
char op,
mkpd_cnt_t cnt,
mkpd_packet_t *packet,
int flag)
{
packet->version = VERSION ;
packet->ptype = ptype ;
packet->op = op ;
packet->cnt = cnt ;
packet->partid = get_my_partid() ;
packet->flag = flag ;
}
/*
* First send the count of data that is going.
* Then send the actual data.
*/
void
mkpd_send_resp_data(int fd, char *c, mkpd_cnt_t cnt)
{
mkpd_packet_t packet ;
char data[PACKET_DATA_LEN] ;
bzero(&packet, sizeof(packet)) ;
bzero(data, sizeof(data)) ;
mkpd_make_req(PACKET_TYPE_COUNT, 0, cnt, &packet, 0) ;
write(fd, &packet, PACKET_REQ_LEN) ;
write(fd, c, cnt) ;
DPRINT(1, ("send_resp_data: %x %d\n", *c, cnt)) ;
}
/* Send err response. This is a 0 in the 1st byte with data len = 1 */
void
mkpd_send_resp_err(int fd)
{
char errbuf[16] ;
*errbuf = 0 ;
mkpd_send_resp_data(fd, errbuf, 1) ;
DPRINT(1,("send_resp_err\n")) ;
}
/*
* Call back routine definitions.
*/
/*
* Get local IP address into dbuf.
*
* Returns:
*
* count of bytes in cnt.
* cnt = 1 and *dbuf = 0 if error.
*/
/* ARGSUSED */
static void
mkpd_prreq_ipaddr(mkpd_packet_t *pkt, char *dbuf, int dbuflen, mkpd_cnt_t *cnt)
{
char name[MKPD_MAX_HOST_NAME_LEN] ;
struct hostent *he ;
char *c = "" ;
char *prefix = MKPD_XPNET_NAME_PREFIX ;
if ((dbuflen <= 0) || (dbuf == NULL))
return ;
if (dbuflen < HOSTADDR_LEN) {
*cnt = 1 ;
*dbuf = 0 ;
return ;
}
strcpy(name, prefix) ;
if (gethostname(name, MKPD_MAX_HOST_NAME_LEN) < 0)
return ;
he = gethostbyname(name) ;
if (he == NULL)
return ;
c = *he->h_addr_list ;
if (!c)
return ;
bcopy(c, dbuf, HOSTADDR_LEN) ;
*cnt = HOSTADDR_LEN ;
DPRINT(1,("ipaddr: %x.%x.%x.%x\n", c[0], c[1], c[2], c[3])) ;
}
/*
* Get the router config map for the local partition.
*/
/* ARGSUSED */
static void
mkpd_prreq_roucfg(mkpd_packet_t *pkt, char *data, int len, mkpd_cnt_t *cnt)
{
part_rou_map_t *pmap = (part_rou_map_t *)data ;
part_rou_map_init(pmap) ;
*cnt = create_my_rou_map(get_my_partid(), pmap, len) ;
if (*cnt < 0) { /* err resp protocol */
*cnt = 1 ;
pmap->cnt = 0 ;
}
DPRINT(1,("roucfg: %d\n", cnt)) ;
}
/* ARGSUSED */
static void
mkpd_prreq_lock(mkpd_packet_t *pkt, char *dbuf, int dbuflen, mkpd_cnt_t *cnt)
{
if (lock < 0) {
lock = pkt->partid ;
*dbuf = 1 ; /* Operation succeeded */
} else
*dbuf = 0 ;
*cnt = 1 ;
}
/* ARGSUSED */
static void
mkpd_prreq_unlock(mkpd_packet_t *pkt, char *dbuf, int dbuflen, mkpd_cnt_t *cnt)
{
if ((pkt->flag) || (lock == pkt->partid)) {
lock = -1 ;
*dbuf = 1 ; /* Operation succeeded */
} else
*dbuf = 0 ;
*cnt = 1 ;
}
/*
* Choose request call back based on request id.
*/
__psunsigned_t
mkpd_get_funcp(unsigned char reqid)
{
struct req_handler *r ;
r = &reqh[0] ;
while (r->reqid) {
if (r->reqid == reqid)
return ((__psunsigned_t)r->funcp) ;
r++ ;
}
return NULL ;
}
/*
* mkpd_update_part_map
*
* Scan partition map returned by syssgi.
* Add new partition info to pfdi.
*
* Return
*
* -1 if mem alloc fails.
*/
int
mkpd_update_part_map(pfdi_t *pfdi)
{
int pcnt ;
part_info_t *tmp_pi ;
int npi = MAX_PARTITIONS ;
int i ;
int rv = 1 ;
tmp_pi = (part_info_t *)malloc(npi * sizeof(part_info_t)) ;
if (tmp_pi == NULL)
return -1 ;
bzero(tmp_pi, npi * sizeof(part_info_t)) ;
pcnt = syssgi(SGI_PART_OPERATIONS,
SYSSGI_PARTOP_PARTMAP, npi, tmp_pi) ;
if (pcnt < 0) {
rv = -1 ;
goto updpm_done ;
}
if (debug)
fprintf(stderr, "np=%d ", pcnt) ;
/* For all partitions found */
for (i=0; i<pcnt; i++) {
/* Is it already taken care of? */
if (pfdiLookup(pfdi, (tmp_pi+i)->pi_partid) >= 0)
continue ;
/* Add it to list */
if (pfdiAdd(pfdi, (tmp_pi + i)) < 0) {
rv = -1 ;
goto updpm_done ;
}
}
updpm_done:
free(tmp_pi) ;
return rv ;
}
/*
* mkpd_open_part_raw
*
* Open raw files of all active partitions.
* Build an fd_set ready for select on read.
*/
void
mkpd_open_part_raw(partid_t myp, pfdi_t *pfdi, fd_set *fds)
{
char name[MKPD_MAX_XRAW_FNAME_LEN] ;
int i ;
int fd ;
char errname[64] ;
for (i=0; i<pfdiCnt(pfdi); i++) {
/* Skip local or open partition */
if (pfdiPartId(pfdi,i) == myp)
continue ;
if (PART_OPEN(pfdi, i)) {
FD_SET(pfdiPartFd(pfdi,i), fds) ;
continue ;
}
/* get path name of partition admin special file */
if (get_raw_path(name, pfdiPartId(pfdi, i)) < 0)
continue ;
fd = open(name, O_RDWR|O_NDELAY) ;
if (fd < 0) {
if (debug) {
sprintf(errname, "Open %s", name) ;
perror(errname) ;
}
mkpd_close_part_raw(pfdi, fds) ;
/* XXX retry if it says resource temp unavailable */
continue ;
} else {
DPRINT(1,("%s: fd = %d\n", name, fd)) ;
}
/* Setup connection to partition i */
pfdiPartFd(pfdi,i) = fd ;
PART_SET_OPEN(pfdi,i) ;
FD_SET(fd, fds) ;
}
}
/*
* mkpd_close_part_raw
*
* close all raw partitions as an error occured in one
* of them.
*/
static void
mkpd_close_part_raw(pfdi_t *pfdi, fd_set *fds)
{
int i ;
int fd ;
for (i=0; i<pfdiCnt(pfdi); i++) {
if (PART_OPEN(pfdi, i)) {
fd = pfdiPartFd(pfdi,i) ;
pfdiPartFd(pfdi, i) = -1 ;
close(fd) ;
PART_SET_CLOSE(pfdi,i) ;
FD_CLR(fd, fds) ;
}
}
}
/*
* process_request
*
* process a request on a file descriptor.
*/
void
process_request( pfdi_t *pfdi,
int lsock,
fd_set *fds,
int maxfds)
{
int i ;
void (*fp)() ;
mkpd_cnt_t cnt ;
mkpd_packet_t packet ;
/* Receive the wanted data in this buffer */
char *data ;
int datalen ;
int opcode ;
bzero(&packet, sizeof(packet)) ;
for (i=0; i<maxfds; i++) {
if (FD_ISSET(i, fds)) {
/* Process request from local socket */
if (i == lsock) {
pr_loc_req(pfdi, lsock) ;
continue ;
}
/* Process req from remote daemon */
/* Read packet of type opcode */
if ((opcode = mkpd_read_req( i,
&packet,
PACKET_TYPE_OPCODE
)) < 0) {
continue ;
}
/* allocate buffer of len given in packet */
datalen = packet.cnt ;
data = (char *)malloc(datalen) ;
if (data == NULL) {
mkpd_send_resp_err(i) ;
continue ;
}
bzero(data, datalen) ;
/* Execute the callback for the reqd op */
if ((fp = (void (*)())mkpd_get_funcp(opcode))) {
(*fp)(&packet, data, datalen, &cnt) ;
mkpd_send_resp_data(i, data, cnt) ;
} else { /* Illegal opcode */
mkpd_send_resp_err(i) ;
}
if (data)
free(data) ;
}
}
}
int
mkpd_select(fd_set *fds)
{
struct timeval t ;
int sel, maxfds ;
maxfds = getdtablehi() ;
init_timeval(&t) ;
sel = select(maxfds, fds, NULL, NULL, &t) ;
return sel ;
}
/*
* mkpart_daemon
*
* Main loop. Serves requests received from any
* active partitions. Keeps looking out for new
* partitions coming up.
*
* Returns: -1 if any error, like mem alloc or
* file open. Does not return otherwise.
*/
int
mkpart_daemon(int lsock, partid_t myp)
{
fd_set rfds ;
pfdi_t *pfdi ;
int sel, maxfds ;
int one = 1 ;
int cnt = 5 ;
if ((pfdi = pfdiInit()) == NULL)
return -1 ;
do {
/*
* Read partition map all over again.
* If new partitions have come up, they will
* be serviced from now on.
*/
if (mkpd_update_part_map(pfdi) < 0)
SLEEP_AND_CONTINUE
/*
* Open all the partition raw files.
*/
FD_ZERO(&rfds) ;
mkpd_open_part_raw(myp, pfdi, &rfds) ;
FD_SET(lsock, &rfds) ;
/*
* Check all of them for any requests. If one
* is available, process the request.
*/
maxfds = getdtablehi() ;
sel = mkpd_select(&rfds) ;
if (sel > 0) {
process_request(pfdi, lsock, &rfds, maxfds) ;
} else if (sel == 0) { /* timed out */
DPRINT(1,(". ")) ;
fflush(stdout) ;
} else {
mkpd_close_part_raw(pfdi, &rfds) ;
}
/* Some testing debug code. */
if ((!cnt--) && (debug == 2)){
cnt = 5 ;
mkpd_close_part_raw(pfdi, &rfds) ;
}
} while (one) ;
/* NOTREACHED */
pfdiFree(pfdi) ;
return -1 ;
}
void
main(int argc, char **argv)
{
partid_t mypid ;
int lsock ;
int one = 1 ;
lock = -1 ;
if (argc > 1)
debug = argv[1][0] - '0' ;
if ((lsock = mkpd_lsock_init()) < 0)
exit(0) ;
if (!debug) {
ignore_signal(SIGINT, SA_RESTART) ;
ignore_signal(SIGTERM, SA_RESTART) ;
ignore_signal(SIGPIPE, SA_RESTART) ;
ignore_signal(SIGHUP, SA_RESTART) ;
}
openlog("mkpd", LOG_PID , LOG_DAEMON);
if (debug)
logmsg("started ...\n") ;
if (0 > _daemonize(debug? (_DF_NOCHDIR|_DF_NOFORK):0,
debug? STDOUT_FILENO:-1,
debug? STDERR_FILENO:-1,
lsock)) {
logmsg("_daemonize failed\n") ;
exit(1) ;
}
while (one) {
/*
* If there are no partitions up yet, try later
*/
if ((mypid = get_my_partid()) == INVALID_PARTID)
SLEEP_AND_CONTINUE
/*
* Try to service mkpart requests. If we fail due
* to any reason, wait and retry the whole thing again.
*/
if (mkpart_daemon(lsock, mypid) < 0)
SLEEP_AND_CONTINUE
}
}
static int
mkpd_lsock_init(void)
{
int lsock ;
struct sockaddr_un sname ;
lsock = socket(PF_UNIX, SOCK_STREAM, 0) ;
if (lsock < 0) {
if (debug >= 1)
perror("socket") ;
goto all_done ;
}
sname.sun_family = AF_UNIX ;
strcpy(sname.sun_path, MKPD_SOCKET_NAME) ;
if (bind(lsock, (void *)&sname, sizeof(sname)) < 0) {
if (!is_mkpd_running()) {
unlink(sname.sun_path) ;
if (bind(lsock, (void *)&sname, sizeof(sname)) < 0) {
logmsg("Unable to use sockets, exiting.\n") ;
if (debug >= 1)
perror("bind") ;
lsock = -1 ;
goto all_done ;
}
} else {
logmsg("mkpd is already running, exiting.\n") ;
if (debug >= 1)
printf("mkpd is already running, exiting.\n") ;
lsock = -1 ;
goto all_done ;
}
}
chmod(sname.sun_path, 00700) ;
if (listen(lsock, MKPD_MAX_SOCKET)) {
if (debug >= 1)
perror("listen") ;
lsock = -1 ;
goto all_done ;
}
all_done:
DPRINT(1,("socket: %d\n", lsock)) ;
return lsock ;
}
void
lock_local(int fd)
{
char status_buf[16] ;
if (lock < 0) {
lock = get_my_partid() ;
*status_buf = 1 ;
} else
*status_buf = 0 ;
mkpd_send_resp_data(fd, status_buf, 1) ;
}
void
unlock_local(int fd, int flag)
{
char status_buf[16] ;
/* If flag, unlock by force. */
if ((flag) || (lock == get_my_partid())) {
lock = -1 ;
*status_buf = 1 ;
} else
*status_buf = 0 ;
mkpd_send_resp_data(fd, status_buf, 1) ;
}
/*
* pr_loc_req
*
* Process a request by the local mkpart command.
* Use sockets for IPC.
*
*/
static void
pr_loc_req(pfdi_t *pfdi, int lsock)
{
mkpd_cnt_t pcnt, dcnt ;
int newfd ;
mkpd_reqbuf_t reqbuf ;
int indx ;
char *buf ;
int buflen ;
/* accept socket connection */
if ((newfd = accept(lsock, 0, 0)) < 0)
return ;
/* read a request buf */
pcnt = read(newfd, &reqbuf, sizeof(mkpd_reqbuf_t)) ;
if (pcnt != sizeof(mkpd_reqbuf_t)) {
if (pcnt >= 0) /* we received something */
mkpd_send_resp_err(newfd) ;
goto close_ret ;
}
if (reqbuf.version != VERSION) {
mkpd_send_resp_err(newfd) ;
goto close_ret ;
}
DPRINT(1,("pr_loc_req: op = %d p = %d\n", reqbuf.op, reqbuf.part)) ;
/* Handle special lock processing for local partition. */
if (reqbuf.part == get_my_partid()) {
if (reqbuf.op == OPCODE_UNLOCK_PART)
unlock_local(newfd, reqbuf.flag) ;
else if (reqbuf.op == OPCODE_LOCK_PART)
lock_local(newfd) ;
else
mkpd_send_resp_err(newfd) ;
goto close_ret ;
}
/* Is the required partition open? */
indx = pfdiLookup(pfdi, reqbuf.part) ;
if ((indx < 0) || (!PART_OPEN(pfdi, indx))) {
mkpd_send_resp_err(newfd) ;
goto close_ret ;
}
/* Alloc memory for request */
buflen = reqbuf.cnt ;
buf = (char *)malloc(buflen) ;
if (buf == NULL)
return ; /* XXX */
dcnt = get_data_from_remote( reqbuf.op, pfdi,
indx, buf, buflen, reqbuf.flag) ;
if (dcnt < 0)
mkpd_send_resp_err(newfd) ;
else
mkpd_send_resp_data(newfd, buf, dcnt) ;
if (buf)
free(buf) ;
close_ret:
close(newfd) ;
}
/*
* get_data_from_remote
*
* When the daemon receives a request from the local mkpart
* it sends a request out to a remote daemon and gets data
* from it.
*
* Returns:
*
* data from remote in databuf, count of valid bytes of data.
* -1 if something is wrong.
*/
static int
get_data_from_remote( char op ,
pfdi_t *pfdi ,
int indx ,
char *databuf,
int dbuflen ,
int flag)
{
mkpd_packet_t packet ;
mkpd_cnt_t cnt = -1, cnt1 ;
int fd ;
char *tmpbuf ;
if ((databuf == NULL) || (dbuflen <= 0))
return -1 ;
if (PART_OPEN(pfdi, indx))
fd = pfdiPartFd(pfdi, indx) ;
else
return -1 ;
/* Send the opcode given by mkpart to the remote daemon. */
mkpd_make_req(PACKET_TYPE_OPCODE, op, dbuflen, &packet, flag) ;
if (write(fd, &packet, PACKET_REQ_LEN) != PACKET_REQ_LEN)
return -1 ;
/* Find out how much data he has to give. */
if ((cnt = mkpd_read_req(fd, &packet, PACKET_TYPE_COUNT)) < 0) {
/* XXX */
return -1 ;
}
/* Alloc a new buffer, if he has lots to give. */
if (cnt > dbuflen) {
tmpbuf = (char *)malloc(cnt) ;
if (tmpbuf == NULL)
return -1 ; /* XXX */
}
else /* Use the supplied buf, it looks enough. */
tmpbuf = databuf ;
if ((cnt1 = read(fd, tmpbuf, cnt)) != cnt) {
if (cnt < 0) /* total read failure */
return -1 ;
else /* got less than expected */
cnt = cnt1 ;
}
/* If we got more, truncate data to dbuflen */
if (cnt > dbuflen) {
bcopy(tmpbuf, databuf, dbuflen) ;
cnt = dbuflen ;
free(tmpbuf) ;
}
DPRINT(1,("get_data_from_remote: cnt = %d\n", cnt)) ;
return cnt ;
}
#include <sys/procfs.h>
#include <dirent.h>
#include <paths.h>
#include <sys/mac.h>
static int
is_mkpd_running(void)
{
DIR *dirp ;
struct dirent *dentp ;
int pdlen ;
char pname[100] ;
struct prpsinfo info ;
int num_mkpd = 0 ;
if ((dirp = opendir(_PATH_PROCFSPI)) == NULL)
/* Assume things are OK. Let it fail elsewhere. */
return(0);
(void) sprintf(pname, "%s%c", _PATH_PROCFSPI, '/');
pdlen = strlen(pname);
while (dentp = readdir(dirp)) {
int procfd; /* fd for /proc/pinfo/nnnnn */
char *plblstring; /* process label string */
if (strcmp(dentp->d_name, ".") == 0 ||
strcmp(dentp->d_name, "..") == 0 ||
(dentp->d_name[0] == '.'))
continue;
plblstring = NULL;
(void) strcpy(pname + pdlen, dentp->d_name);
if ((procfd = open(pname, O_RDONLY)) == -1) {
mac_free(plblstring);
continue;
}
if (ioctl(procfd, PIOCPSINFO, (char *) &info) == -1) {
(void) close(procfd);
continue ;
}
(void) close(procfd);
if (strstr(info.pr_fname, "mkpd"))
num_mkpd ++ ;
}
(void) closedir(dirp);
if (num_mkpd > 1)
return 1 ;
else
return 0 ;
}