📄 sd_rexd.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)sd_rexd.c 1.1 92/07/30 Copyright Sun Micro";#endif/* * sd_rexd - Sundiag's remote execution daemon based on rexd. * * Copyright (c) 1985 Sun Microsystems, Inc. */#include <sys/param.h>#include <rpc/rpc.h>#include <stdio.h>#include <netdb.h>#include <signal.h>#include <sys/socket.h>#include <sys/wait.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <fcntl.h>#include <mntent.h>#include <errno.h>#include <rpcsvc/rex.h>#include "sundiag_rpcnums.h"# define ListnerTimeout 300 /* seconds listner stays alive */# define WaitLimit 10 /* seconds to wait after io is closed */# define TempDir "/tmp_rex" /* directory to hold temp mounts */# define TempName "/tmp_rex/sd_rexdXXXXXX" /* name template for temp mount points */# define TempMatch 13 /* unique prefix of above */#define PROGRAMNAME "sd_rexd"SVCXPRT *ListnerTransp; /* non-null means still a listner */static char **Argv; /* saved argument vector (for ps) */static char *LastArgv; /* saved end-of-argument vector */int OutputSocket; /* socket for stop/cont notification */int MySocket; /* transport socket */int HasHelper = 0; /* must kill helpers (interactive mode) */int debug = 0;extern int Master; /* half of the pty */main(argc, argv) int argc; char **argv;{ /* * the server is a typical RPC daemon, except that we only * accept TCP connections. */ struct sockaddr_in addr; int len = sizeof(struct sockaddr_in); int dorex(), ListnerTimer(), CatchChild(); char c; int fdes = 0; /* * Remember the start and extent of argv for setproctitle(). * Open the console for error printouts, but don't let it be * our controlling terminal. */ if (geteuid()) { fprintf(stderr, "sd_rexd: must be super-user to run\n"); exit(1); } while ((c=getopt(argc, argv, "d")) != EOF) { switch(c) { case 'd': debug = 1; break; } } if (debug) printf("%s started.\n", PROGRAMNAME); Argv = argv; if (argc > 0) LastArgv = argv[argc-1] + strlen(argv[argc-1]); else LastArgv = NULL; close(1); /* close stdout */ close(2); /* close stderr */ /* * redirect stdout (file descriptor 1) to console * since open returns the lowest number fd available. */ /* fdes = open("/dev/console", 1); */ fdes = open("/dev/tty", 1); if (debug) printf("opening /dev/console returned fd = %d\n", fdes); fdes = dup(1); if (debug) printf("dup(1) returned fd = %d\n", fdes); /* NoControl(); */ signal(SIGCHLD, CatchChild); signal(SIGPIPE, SIG_IGN); signal(SIGALRM, ListnerTimer); if (issock(0)) { if (debug) printf("started from inetd.\n"); /* * Started from inetd: use fd 0 as socket */ if ((ListnerTransp = svctcp_create(0, 0, 0)) == NULL) { fprintf(stderr, "sd_rexd: svctcp_create error\n"); exit(1); } if (!svc_register(ListnerTransp, SD_REXPROG, SD_REXVERS, dorex, 0)) { fprintf(stderr, "sd_rexd: service register error\n"); exit(1); } alarm(ListnerTimeout); } else { /* * Started from shell, background thyself and run forever. */ int pid = fork(); if (pid < 0) { perror("rpc.rexd: can't fork"); exit(1); } if (pid) { if (debug) printf("parent exiting. pid = %d.\n", pid); exit(0); } if ((ListnerTransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { fprintf(stderr, "sd_rexd: svctcp_create: error\n"); exit(1); } if (debug) printf("started from shell. pid = %d.\n", pid); pmap_unset(SD_REXPROG, SD_REXVERS); if (!svc_register(ListnerTransp, SD_REXPROG, SD_REXVERS, dorex, IPPROTO_TCP)) { fprintf(stderr, "sd_rexd: service rpc register: error\n"); exit(1); } if (debug) printf("dorex registered.\n"); } /* * Create a private temporary directory to hold sd_rexd's mounts */ if (mkdir (TempDir, 0777) < 0) { if (errno != EEXIST) { perror ("sd_rexd: mkdir"); fprintf (stderr, "sd_rexd: can't create temp directory %s\n", TempDir); exit (1); } else if (debug) printf("temp directory %s already exists.\n", TempDir); } else if (debug) printf("made temp directory %s.\n", TempDir);/* * normally we would call svc_run() at this point, but we need to be informed * of when the RPC connection is broken, in case the other side crashes. */ while (TRUE) { extern int errno; fd_set readfds; if (MySocket && !FD_ISSET(MySocket, &svc_fdset) ) { char *waste; /* * This is when the connection dies for some * random reason, e.g. client crashes. */ (void) rex_wait(&waste); rex_cleanup(); exit(1); } readfds = svc_fdset; switch (select(FD_SETSIZE, &readfds, (int *)0, (int *)0, 0)) { case -1: if (errno == EINTR) continue; perror("sd_rexd: select failed"); exit(1); case 0: fprintf(stderr,"sd_rexd: Select returned zero\r\n"); continue; default: if (HasHelper) HelperRead(&readfds); svc_getreqset(&readfds); } }}/* * This function gets called after the listner has timed out waiting * for any new connections coming in. */ListnerTimer(){ svc_destroy(ListnerTransp); exit(0);}/* * dorex - handle one of the rex procedure calls, dispatching to the * correct function. */dorex(rqstp, transp) register struct svc_req *rqstp; register SVCXPRT *transp;{ struct rex_start *rst; struct rex_result result; if (ListnerTransp) { /* * First call - fork a server for this connection */ int fd, pid, count; if (debug) printf("entering dorex. still a listner.\n"); for (count=0; (pid = fork()) < 0; count++) { if (count > 4) { perror("sd_rexd: cannot fork"); break; } sleep(5); } if (pid != 0) { /* * Parent - return to service loop to accept further * connections. */ if (debug) printf("dorex: parent; return to service loop.\n"); /* alarm(ListnerTimeout); */ svc_destroy (transp); return; } /* * child - close listner transport to avoid confusion * Also need to close all other service transports * besides the one we are interested in. * Save ours so that we know when it goes away. */ alarm(0); if (transp != ListnerTransp) { close(ListnerTransp->xp_sock); xprt_unregister(ListnerTransp); if (debug) printf("transp != ListnerTransp\n"); } ListnerTransp = NULL; MySocket = transp->xp_sock; for (fd=0; fd<FD_SETSIZE; fd++) if (fd != transp->xp_sock && FD_ISSET(fd, &svc_fdset) ) { close(fd); FD_CLR(fd, &svc_fdset); } if (debug) printf("dorex: child; closed listner transport.\n"); } switch (rqstp->rq_proc) { case NULLPROC: if (svc_sendreply(transp, xdr_void, 0) == FALSE) { fprintf(stderr, "sd_rexd: nullproc err"); exit(1); } return; case REXPROC_START: rst = (struct rex_start *)malloc(sizeof (struct rex_start)); bzero((char *)rst, sizeof *rst); if (svc_getargs(transp, xdr_rex_start, rst) == FALSE) { svcerr_decode(transp); exit(1); } if (rqstp->rq_cred.oa_flavor != AUTH_UNIX) { svcerr_auth(transp); exit(1); } result.rlt_stat = rex_start(rst, (struct authunix_parms *)rqstp->rq_clntcred, &result.rlt_message, transp->xp_sock); if (svc_sendreply(transp, xdr_rex_result, &result) == FALSE) { fprintf(stderr, "sd_rexd: reply failed\n"); rex_cleanup(); exit(1); } if (result.rlt_stat) { rex_cleanup(); exit(0); } return; case REXPROC_MODES: { struct rex_ttymode mode; if (svc_getargs(transp, xdr_rex_ttymode, &mode)==FALSE) { svcerr_decode(transp); exit(1); } SetPtyMode(&mode); if (svc_sendreply(transp, xdr_void, 0) == FALSE) { fprintf(stderr, "sd_rexd: mode reply failed"); exit(1); } } return; case REXPROC_WINCH: { struct ttysize size; if (svc_getargs(transp, xdr_rex_ttysize, &size)==FALSE) { svcerr_decode(transp); exit(1); } SetPtySize(&size); if (svc_sendreply(transp, xdr_void, 0) == FALSE) { fprintf(stderr, "sd_rexd: window change reply failed"); exit(1); } } return; case REXPROC_SIGNAL: { int sigNumber; if (svc_getargs(transp, xdr_int, &sigNumber)==FALSE) { svcerr_decode(transp); exit(1); } SendSignal(sigNumber); if (svc_sendreply(transp, xdr_void, 0) == FALSE) { fprintf(stderr, "sd_rexd: signal reply failed"); exit(1); } } return; case REXPROC_WAIT: result.rlt_stat = rex_wait(&result.rlt_message); if (svc_sendreply(transp, xdr_rex_result, &result) == FALSE) { fprintf(stderr, "sd_rexd: reply failed\n"); exit(1); } rex_cleanup(); exit(0); /* NOTREACHED */ default: svcerr_noproc(transp); exit(1); }}int child = 0; /* pid of the executed process */int ChildStatus = 0; /* saved return status of child */int ChildDied = 0; /* true when above is valid */char nfsdir[MAXPATHLEN]; /* file system we mounted */char *tmpdir; /* where above is mounted, NULL if none *//* * signal handler for SIGCHLD - called when user process dies or is stopped */CatchChild(){ int pid; union wait status; while ((pid = wait3(&status, WNOHANG|WUNTRACED, NULL)) > 0) { if (pid==child) { if (WIFSTOPPED(status)) { send(OutputSocket, "", 1, MSG_OOB); /* tell remote client to stop */ sigpause(0); /* wait for SIGURG */ killpg(child, SIGCONT); /* restart child */ return; } ChildStatus = status.w_retcode; ChildDied = 1; if (HasHelper && !FD_ISSET (Master, &svc_fdset)) { KillHelper(child); HasHelper = 0; } } }}/* * oob -- called when we should restart the stopped child. */oob(){ int atmark; char waste[BUFSIZ], mark; for (;;) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -