@ -0,0 +1,456 @@ |
|||
#include <stdint.h> |
|||
#include <errno.h> |
|||
#include <stdio.h> |
|||
#include <unistd.h> |
|||
#include <signal.h> |
|||
#include <stdlib.h> |
|||
#include <netinet/in.h> |
|||
#include <arpa/inet.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/types.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/time.h> |
|||
#include <sys/wait.h> |
|||
#include <string.h> |
|||
#include <fcntl.h> |
|||
|
|||
#define TCPPORT 28336 |
|||
|
|||
#define CMD_EXEC 1 |
|||
#define CMD_ADDARG 2 |
|||
#define CMD_ADDENV 3 |
|||
#define CMD_CHDIR 4 |
|||
#define CMD_CHROOT 5 |
|||
#define CMD_EXIT 6 |
|||
#define CMD_BUILDID 7 |
|||
#define CMD_WRITE0 1000 |
|||
#define CMD_CLOSE0 2000 |
|||
#define CMD_ENABLE0 3000 |
|||
|
|||
struct pn_pkg { |
|||
uint32_t len; |
|||
uint32_t type; |
|||
char data[]; |
|||
}; |
|||
|
|||
struct sbuf; |
|||
struct sbuf { |
|||
struct sbuf *next; |
|||
int len, c; |
|||
struct pn_pkg *p; |
|||
char *d; |
|||
}; |
|||
|
|||
struct sbuf *recv4p = 0; |
|||
struct sbuf *send2p = 0; |
|||
int sbuf_c = 0; |
|||
|
|||
void conn_send(int conn, int len, int type, char *data) |
|||
{ |
|||
struct pn_pkg *p = malloc( sizeof(struct pn_pkg) + len ); |
|||
int i, rc; |
|||
|
|||
p->len = htonl(len); |
|||
p->type = htonl(type); |
|||
|
|||
memcpy(p->data, data, len); |
|||
|
|||
len += sizeof(struct pn_pkg); |
|||
for (i = 0; i < len; i += rc) { |
|||
rc = write(conn, (char*)p + i, len - i); |
|||
if ( rc <= 0 ) { |
|||
fprintf(stderr, "network write error: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
} |
|||
|
|||
free(p); |
|||
} |
|||
|
|||
int conn_read(int conn, char *buf, int len, int nonblock) |
|||
{ |
|||
int f = -1; |
|||
|
|||
if ( nonblock ) { |
|||
f = fcntl(conn, F_GETFL, 0); |
|||
fcntl(conn, F_SETFL, f | O_NONBLOCK); |
|||
} |
|||
|
|||
while (len) { |
|||
int rc = read(conn, buf, len); |
|||
if ( rc < 0 ) { |
|||
if ( errno == EAGAIN ) break; |
|||
fprintf(stderr, "network read error: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
if ( rc == 0 ) { |
|||
fprintf(stderr, "connection closed by peer\n"); |
|||
exit(-1); |
|||
} |
|||
if ( f != -1 ) |
|||
fcntl(conn, F_SETFL, f); |
|||
len -= rc; buf += rc; f = -1; |
|||
} |
|||
|
|||
if ( f != -1 ) |
|||
fcntl(conn, F_SETFL, f); |
|||
return len; |
|||
} |
|||
|
|||
struct pn_pkg *conn_recv(int conn, int nonblock) |
|||
{ |
|||
struct pn_pkg *p = malloc( sizeof(struct pn_pkg) ); |
|||
|
|||
if ( conn_read(conn, (char*)p, 8, nonblock) ) { |
|||
free(p); |
|||
return 0; |
|||
} |
|||
|
|||
p->len = ntohl(p->len); |
|||
p->type = ntohl(p->type); |
|||
|
|||
p = realloc(p, sizeof(struct pn_pkg) + p->len); |
|||
conn_read(conn, p->data, p->len, 0); |
|||
|
|||
return p; |
|||
} |
|||
|
|||
void do_chroot(char *d, char *b) |
|||
{ |
|||
char buf[1024]; |
|||
char *e = malloc(strlen(d)+strlen(b)+2); |
|||
int i; |
|||
|
|||
sprintf(e, "%s:%s", d, b); |
|||
for (i=0; e[i]; i++) if ( e[i] == '/' ) e[i] = '_'; |
|||
snprintf(buf, 1024, "%s/pseudonative_handler", e); |
|||
|
|||
if ( access(buf, F_OK) ) { |
|||
mkdir(e, 0700); |
|||
snprintf(buf, 1024, "mount -t nfs -o noac %s/build/%s %s", d, b, e); |
|||
system(buf); |
|||
snprintf(buf, 1024, "mount -t nfs -o noac %s %s/ROCK/loop", d, e); |
|||
system(buf); |
|||
snprintf(buf, 1024, "mount -t nfs -o noac %s/config %s/ROCK/config", d, e); |
|||
system(buf); |
|||
snprintf(buf, 1024, "mount -t nfs -o noac %s/download %s/ROCK/download", d, e); |
|||
system(buf); |
|||
snprintf(buf, 1024, "mount -t proc none %s/proc", e); |
|||
system(buf); |
|||
} |
|||
|
|||
chdir(e); |
|||
chroot("."); |
|||
|
|||
free(e); |
|||
} |
|||
|
|||
void do_session(int conn) |
|||
{ |
|||
char *argv[1024], *bid="", *exe = "/bin/true"; |
|||
int f0[2], f1[2], f2[2], m, f, argc = 0; |
|||
int open_0 = 1, open_1 = 1, open_2 = 1; |
|||
int schedule_close_0 = 0, enable_0 = 0; |
|||
unsigned char retval; |
|||
struct timeval tv; |
|||
fd_set rfds, wfds; |
|||
struct pn_pkg *p; |
|||
|
|||
clearenv(); |
|||
signal(SIGCHLD, SIG_DFL); |
|||
signal(SIGPIPE, SIG_IGN); |
|||
|
|||
while (1) { |
|||
if ( (p = conn_recv(conn, 0)) == 0 ) { |
|||
fprintf(stderr, "\nnetwork read error: EOF\n"); |
|||
exit(-1); |
|||
} |
|||
|
|||
switch (p->type) { |
|||
case CMD_EXEC: |
|||
printf("\nEXE: %s", p->data); |
|||
exe = strdup(p->data); |
|||
break; |
|||
case CMD_ADDARG: |
|||
printf(m == p->type ? " %s" : "\nARG: %s", p->data); |
|||
argv[argc++] = strdup(p->data); |
|||
break; |
|||
case CMD_ADDENV: |
|||
printf(m == p->type ? "." : "\nENV: ."); |
|||
putenv(strdup(p->data)); |
|||
break; |
|||
case CMD_CHDIR: |
|||
printf("\nCHD: %s", p->data); |
|||
chdir(p->data); |
|||
break; |
|||
case CMD_BUILDID: |
|||
bid = strdup(p->data); |
|||
break; |
|||
case CMD_CHROOT: |
|||
printf("\nMNT: %s %s", p->data, bid); |
|||
do_chroot(p->data, bid); |
|||
break; |
|||
} |
|||
|
|||
if ((m=p->type) == CMD_EXEC) { |
|||
free(p); |
|||
break; |
|||
} |
|||
|
|||
free(p); |
|||
} |
|||
|
|||
pipe(f0); |
|||
pipe(f1); |
|||
pipe(f2); |
|||
|
|||
printf("\n"); |
|||
fflush(stderr); |
|||
fflush(stdout); |
|||
|
|||
if (!fork()) { |
|||
dup2(f0[0], 0); close(f0[0]); close(f0[1]); |
|||
dup2(f1[1], 1); close(f1[0]); close(f1[1]); |
|||
dup2(f2[1], 2); close(f2[0]); close(f2[1]); |
|||
signal(SIGPIPE, SIG_DFL); |
|||
|
|||
argv[argc] = 0; |
|||
execv(exe, argv); |
|||
fprintf(stderr, "Can't execute %s: %s\n", exe, strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
|
|||
close(f0[0]); |
|||
close(f1[1]); |
|||
close(f2[1]); |
|||
|
|||
/* This is usefull for reading strace dumps, etc. */ |
|||
#if 0 |
|||
printf("FDS: fd0=%d, fd1=%d, fd2=%d, conn=%d\n", |
|||
f0[1], f1[0], f2[0], conn); |
|||
#endif |
|||
|
|||
f = fcntl(f0[1], F_GETFL, 0); |
|||
fcntl(f0[1], F_SETFL, f | O_NONBLOCK); |
|||
|
|||
f = fcntl(f1[0], F_GETFL, 0); |
|||
fcntl(f1[0], F_SETFL, f | O_NONBLOCK); |
|||
|
|||
f = fcntl(f2[0], F_GETFL, 0); |
|||
fcntl(f2[0], F_SETFL, f | O_NONBLOCK); |
|||
|
|||
while (open_1 || open_2) |
|||
{ |
|||
char buf[512]; |
|||
int rc; |
|||
|
|||
FD_ZERO(&rfds); |
|||
FD_ZERO(&wfds); |
|||
|
|||
m = f0[1]; |
|||
if ( conn > m ) m = conn; FD_SET(conn, &rfds); |
|||
if ( open_1 ) { if ( f1[0] > m ) m = f1[0]; FD_SET(f1[0], &rfds); } |
|||
if ( open_2 ) { if ( f2[0] > m ) m = f2[0]; FD_SET(f2[0], &rfds); } |
|||
|
|||
write(1, "?", 1); |
|||
|
|||
tv.tv_sec = 1; |
|||
tv.tv_usec = 0; |
|||
|
|||
if ( schedule_close_0 < 2 && (send2p || !enable_0) ){ |
|||
FD_SET(f0[1], &wfds); |
|||
rc = select(m+1, &rfds, &wfds, 0, &tv); |
|||
} else |
|||
rc = select(m+1, &rfds, 0, 0, &tv); |
|||
|
|||
if ( rc < 0 && errno != EINTR ) { |
|||
fprintf(stderr, "select error: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
|
|||
/* FIXME: This should only be triggered if the proc is actually |
|||
* sleeping (read(), poll(), select(), etc) on input */ |
|||
if ( !enable_0 && FD_ISSET(f0[1], &wfds) ) { |
|||
write(1, "E", 1); |
|||
conn_send(conn, 0, CMD_ENABLE0, 0); |
|||
enable_0 = 1; |
|||
} |
|||
|
|||
nextread: |
|||
if ( schedule_close_0 == 2 ) |
|||
goto skip_send2p; |
|||
|
|||
while ( send2p ) |
|||
{ |
|||
struct sbuf *t; |
|||
|
|||
while ( send2p->len > 0 ) { |
|||
rc = write(f0[1], send2p->d, send2p->len); |
|||
if ( rc <= 0 ) { |
|||
if ( errno == EAGAIN ) goto skip_send2p; |
|||
if ( errno == EPIPE ) { |
|||
write(1, "[P]", 3); |
|||
conn_send(conn, 0, CMD_CLOSE0, 0); |
|||
schedule_close_0 = 2; |
|||
goto skip_send2p; |
|||
} |
|||
fprintf(stderr, "write error (%d): %s\n", f0[1], strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
send2p->len -= rc; |
|||
send2p->d += rc; |
|||
fflush(stdout); |
|||
} |
|||
|
|||
write(1, "X", 1); |
|||
|
|||
send2p = (t = send2p)->next; |
|||
free(t->p); free(t); |
|||
} |
|||
if ( !send2p ) { |
|||
recv4p = 0; |
|||
if ( schedule_close_0 ) { |
|||
schedule_close_0 = 2; |
|||
write(1, "[X]", 3); |
|||
close(f0[1]); |
|||
} |
|||
} |
|||
skip_send2p:; |
|||
|
|||
if ( (p = conn_recv(conn, 1)) ) { |
|||
if ( p->type == CMD_WRITE0 && open_0 ) { |
|||
struct sbuf *t = malloc(sizeof(struct sbuf)); |
|||
|
|||
t->next = 0; |
|||
t->p = p; |
|||
t->len = p->len; |
|||
t->d = p->data; |
|||
t->c = sbuf_c++; |
|||
|
|||
if ( recv4p ) |
|||
recv4p->next = t; |
|||
else |
|||
send2p = t; |
|||
recv4p = t; |
|||
|
|||
write(1, "0", 1); |
|||
|
|||
goto nextread; |
|||
} |
|||
if ( p->type == CMD_CLOSE0 ) { |
|||
write(1, "[0]", 3); |
|||
if ( !schedule_close_0 ) |
|||
schedule_close_0 = 1; |
|||
open_0 = 0; |
|||
} |
|||
if ( p->type == CMD_CLOSE0+1 ) { |
|||
write(1, "[P1]", 4); |
|||
close(f1[0]); |
|||
open_1 = 0; |
|||
} |
|||
if ( p->type == CMD_CLOSE0+2 ) { |
|||
write(1, "[P2]", 4); |
|||
close(f2[0]); |
|||
open_2 = 0; |
|||
} |
|||
free(p); |
|||
goto nextread; |
|||
} |
|||
|
|||
if( open_1 ) |
|||
{ |
|||
rc = read(f1[0], buf, 512); |
|||
if ( rc > 0 ) { |
|||
write(1, "1", 1); |
|||
conn_send(conn, rc, CMD_WRITE0+1, buf); |
|||
goto nextread; |
|||
} else if (rc == 0) { |
|||
write(1, "[1]", 3); |
|||
conn_send(conn, 0, CMD_CLOSE0+1, 0); |
|||
open_1 = 0; |
|||
} else if ( errno != EAGAIN ) { |
|||
perror("Error on read from f1:"); |
|||
} |
|||
} |
|||
|
|||
if( open_2 ) |
|||
{ |
|||
rc = read(f2[0], buf, 512); |
|||
if ( rc > 0 ) { |
|||
write(1, "2", 1); |
|||
conn_send(conn, rc, CMD_WRITE0+2, buf); |
|||
goto nextread; |
|||
} else if (rc == 0) { |
|||
write(1, "[2]", 3); |
|||
conn_send(conn, 0, CMD_CLOSE0+2, 0); |
|||
open_2 = 0; |
|||
} else if ( errno != EAGAIN ) { |
|||
perror("Error on read from f2:"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
write(1, "\n", 1); |
|||
|
|||
wait(&m); |
|||
retval = WEXITSTATUS(m); |
|||
conn_send(conn, 1, CMD_EXIT, &retval); |
|||
printf("RET: %d\n", retval); |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
struct sockaddr_in addr; |
|||
int listenfd, fd; |
|||
|
|||
printf("\n"); |
|||
printf("**********************************************************************\n"); |
|||
printf("* *\n"); |
|||
printf("* ROCK Linux Pseudo-Native Daemon by Clifford Wolf *\n"); |
|||
printf("* *\n"); |
|||
printf("* This daemon will create subdirectories in the current working *\n"); |
|||
printf("* directory and mount NFS shares there. There is no authentication *\n"); |
|||
printf("* implemented - so everyone who can reach the TCP port can also *\n"); |
|||
printf("* execute commands. So secure the port using iptables! *\n"); |
|||
printf("* *\n"); |
|||
printf("**********************************************************************\n"); |
|||
printf("\n"); |
|||
|
|||
signal(SIGCHLD, SIG_IGN); |
|||
|
|||
if ( (listenfd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { |
|||
fprintf(stderr, "socket: %s\n", strerror(errno)); |
|||
return 1; |
|||
} |
|||
|
|||
bzero(&addr,sizeof(addr)); |
|||
addr.sin_family=AF_INET; |
|||
addr.sin_addr.s_addr = htonl(INADDR_ANY); |
|||
addr.sin_port = htons(TCPPORT); |
|||
|
|||
if ( bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ) { |
|||
fprintf(stderr, "bind: %s\n", strerror(errno)); |
|||
return 1; |
|||
} |
|||
|
|||
if ( listen(listenfd, 5) == -1 ) { |
|||
fprintf(stderr, "listen: %s\n", strerror(errno)); |
|||
return 1; |
|||
} |
|||
|
|||
printf("Listening on TCP port %d ...\n", TCPPORT); |
|||
while (1) { |
|||
if ( (fd=accept(listenfd, NULL, NULL)) == -1 ) { |
|||
fprintf(stderr, "accept: %s\n", strerror(errno)); |
|||
return 1; |
|||
} |
|||
if ( !fork() ) { |
|||
fprintf(stderr, "\nconnection %d opened.", (int)getpid()); |
|||
do_session(fd); |
|||
return 0; |
|||
} else close(fd); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
@ -0,0 +1,423 @@ |
|||
#include <stdio.h> |
|||
#include <libgen.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <stdlib.h> |
|||
#include <stdint.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/time.h> |
|||
#include <netinet/in.h> |
|||
#include <arpa/inet.h> |
|||
#include <fcntl.h> |
|||
#include <glob.h> |
|||
#include <signal.h> |
|||
|
|||
extern char **environ; |
|||
|
|||
#define LIBDIR "/ROCK/tools.cross/pseudonative.lib" |
|||
|
|||
#define BINDIR_1 "/ROCK/tools.cross/pseudonative.bin" |
|||
#define BINDIR_2 "/ROCK/tools.cross/bin" |
|||
#define BINDIR_SIZE 100 |
|||
|
|||
#define TCPPORT 28336 |
|||
|
|||
#define CMD_EXEC 1 |
|||
#define CMD_ADDARG 2 |
|||
#define CMD_ADDENV 3 |
|||
#define CMD_CHDIR 4 |
|||
#define CMD_CHROOT 5 |
|||
#define CMD_EXIT 6 |
|||
#define CMD_BUILDID 7 |
|||
#define CMD_WRITE0 1000 |
|||
#define CMD_CLOSE0 2000 |
|||
#define CMD_ENABLE0 3000 |
|||
|
|||
int config_debug = 0; |
|||
int config_remote = 0; |
|||
|
|||
struct pn_pkg { |
|||
uint32_t len; |
|||
uint32_t type; |
|||
char data[]; |
|||
}; |
|||
|
|||
int conn_open(const char *peer) |
|||
{ |
|||
struct sockaddr_in sin; |
|||
int conn; |
|||
|
|||
sin.sin_family = PF_INET; |
|||
sin.sin_port = htons(TCPPORT); |
|||
|
|||
if ( !inet_aton(peer, &sin.sin_addr) ) { |
|||
fprintf(stderr, "pseudonative_handler: can't parse address '%s'\n", peer); |
|||
exit(-1); |
|||
} |
|||
|
|||
conn = socket(PF_INET, SOCK_STREAM, 0); |
|||
if (conn < 0) { |
|||
fprintf(stderr, "pseudonative_handler: can't create socket: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
|
|||
if (connect(conn, (struct sockaddr *)&sin, sizeof (sin)) < 0) { |
|||
fprintf(stderr, "pseudonative_handler: can't connect to remote host: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
|
|||
return conn; |
|||
} |
|||
|
|||
void conn_send(int conn, int len, int type, char *data) |
|||
{ |
|||
struct pn_pkg *p = malloc( sizeof(struct pn_pkg) + len ); |
|||
int i, rc; |
|||
|
|||
p->len = htonl(len); |
|||
p->type = htonl(type); |
|||
|
|||
memcpy(p->data, data, len); |
|||
|
|||
len += sizeof(struct pn_pkg); |
|||
for (i = 0; i < len; i += rc) { |
|||
rc = write(conn, (char*)p + i, len - i); |
|||
if ( rc <= 0 ) { |
|||
if ( errno == ECONNRESET && type == CMD_CLOSE0 ) break; |
|||
fprintf(stderr, "pseudonative_handler: network write error: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
} |
|||
|
|||
free(p); |
|||
} |
|||
|
|||
int conn_read(int conn, char *buf, int len, int nonblock) |
|||
{ |
|||
int f = -1; |
|||
|
|||
if ( nonblock ) { |
|||
f = fcntl(conn, F_GETFL, 0); |
|||
fcntl(conn, F_SETFL, f | O_NONBLOCK); |
|||
} |
|||
|
|||
while (len) { |
|||
int rc = read(conn, buf, len); |
|||
if ( rc < 0 ) { |
|||
if ( errno == EAGAIN ) break; |
|||
fprintf(stderr, "pseudonative_handler: network read error: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
if ( rc == 0 ) { |
|||
fprintf(stderr, "pseudonative_handler: connection closed by peer\n"); |
|||
exit(-1); |
|||
} |
|||
if ( f != -1 ) |
|||
fcntl(conn, F_SETFL, f); |
|||
len -= rc; buf += rc; f = -1; |
|||
} |
|||
|
|||
if ( f != -1 ) |
|||
fcntl(conn, F_SETFL, f); |
|||
return len; |
|||
} |
|||
|
|||
struct pn_pkg *conn_recv(int conn) |
|||
{ |
|||
struct pn_pkg *p = malloc( sizeof(struct pn_pkg) ); |
|||
|
|||
if ( conn_read(conn, (char*)p, 8, 1) ) { |
|||
free(p); |
|||
return 0; |
|||
} |
|||
|
|||
p->len = ntohl(p->len); |
|||
p->type = ntohl(p->type); |
|||
|
|||
p = realloc(p, sizeof(struct pn_pkg) + p->len); |
|||
conn_read(conn, p->data, p->len, 0); |
|||
|
|||
return p; |
|||
} |
|||
|
|||
int exec_remote(char ** argv) |
|||
{ |
|||
char buf[1024], *txt; |
|||
int ret = -1, open_0 = 1; |
|||
int enable_0 = 0; |
|||
int f, i, conn, rc; |
|||
struct timeval tv; |
|||
struct pn_pkg *p; |
|||
fd_set rfds; |
|||
|
|||
/* connect */ |
|||
txt = getenv("ROCKCFG_PSEUDONATIVE_NATIVEHOST"); |
|||
if ( txt && *txt ) { |
|||
conn = conn_open(txt); |
|||
} else { |
|||
fprintf(stderr, "pseudonative_handler: no native host configured\n"); |
|||
exit(-1); |
|||
} |
|||
|
|||
/* send build id */ |
|||
txt = getenv("ROCKCFG_ID"); |
|||
if ( txt && *txt ) |
|||
conn_send(conn, strlen(txt)+1, CMD_BUILDID, txt); |
|||
|
|||
/* mount and chroot */ |
|||
txt = getenv("ROCKCFG_PSEUDONATIVE_NFSROOT"); |
|||
if ( txt && *txt ) |
|||
conn_send(conn, strlen(txt)+1, CMD_CHROOT, txt); |
|||
|
|||
/* current directory */ |
|||
if ( getcwd(buf, 1024) ) |
|||
conn_send(conn, strlen(buf)+1, CMD_CHDIR, buf); |
|||
|
|||
/* send environment */ |
|||
for (i=0; environ[i]; i++) |
|||
conn_send(conn, strlen(environ[i])+1, CMD_ADDENV, environ[i]); |
|||
|
|||
/* send arguments */ |
|||
for (i=0; argv[i]; i++) |
|||
conn_send(conn, strlen(argv[i])+1, CMD_ADDARG, argv[i]); |
|||
|
|||
/* execute command */ |
|||
conn_send(conn, strlen(argv[0])+1, CMD_EXEC, argv[0]); |
|||
|
|||
/* we pass sigpipe's to peer */ |
|||
signal(SIGPIPE, SIG_IGN); |
|||
|
|||
while (1) |
|||
{ |
|||
FD_ZERO(&rfds); |
|||
if ( open_0 && enable_0 ) FD_SET(0, &rfds); |
|||
FD_SET(conn, &rfds); |
|||
|
|||
nextselect: |
|||
tv.tv_sec = 1; |
|||
tv.tv_usec = 0; |
|||
rc = select(conn+1, &rfds, 0, 0, &tv); |
|||
|
|||
if ( rc < 0 ) { |
|||
if ( errno == EINTR ) goto nextselect; |
|||
fprintf(stderr, "pseudonative_handler: select error: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
|
|||
nextread: |
|||
if ( (p = conn_recv(conn)) != 0 ) { |
|||
char *d = p->data; |
|||
|
|||
switch (p->type) { |
|||
case CMD_WRITE0+1: |
|||
while ( p->len ) { |
|||
rc = write(1, d, p->len); |
|||
if ( rc <= 0 ) { |
|||
if ( errno == EPIPE ) { |
|||
conn_send(conn, 0, CMD_CLOSE0+1, 0); |
|||
break; |
|||
} |
|||
fprintf(stderr, "pseudonative_handler: write error on fd1: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
d += rc; p->len -= rc; |
|||
} |
|||
break; |
|||
case CMD_WRITE0+2: |
|||
while ( p->len ) { |
|||
rc = write(2, d, p->len); |
|||
if ( rc <= 0 ) { |
|||
if ( errno == EPIPE ) { |
|||
conn_send(conn, 0, CMD_CLOSE0+2, 0); |
|||
break; |
|||
} |
|||
fprintf(stderr, "pseudonative_handler: write error on fd2: %s\n", strerror(errno)); |
|||
exit(-1); |
|||
} |
|||
d += rc; p->len -= rc; |
|||
} |
|||
break; |
|||
case CMD_CLOSE0: |
|||
close(0); |
|||
open_0 = 0; |
|||
break; |
|||
case CMD_CLOSE0+1: |
|||
close(1); |
|||
break; |
|||
case CMD_CLOSE0+2: |
|||
close(2); |
|||
break; |
|||
case CMD_ENABLE0: |
|||
enable_0 = 1; |
|||
break; |
|||
case CMD_EXIT: |
|||
ret = (unsigned char)p->data[0]; |
|||
free(p); |
|||
goto finish; |
|||
} |
|||
free(p); |
|||
goto nextread; |
|||
} |
|||
|
|||
if( open_0 && enable_0 ) |
|||
{ |
|||
f = fcntl(0, F_GETFL, 0); |
|||
fcntl(0, F_SETFL, f | O_NONBLOCK); |
|||
|
|||
rc = read(0, buf, 512); |
|||
|
|||
fcntl(0, F_SETFL, f); |
|||
|
|||
if ( rc > 0 ) { |
|||
conn_send(conn, rc, CMD_WRITE0, buf); |
|||
goto nextread; |
|||
} else if (rc == 0) { |
|||
conn_send(conn, 0, CMD_CLOSE0, 0); |
|||
open_0 = 0; |
|||
} else if ( errno != EAGAIN ) { |
|||
perror("Error on read from f2:"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
finish: |
|||
close(conn); |
|||
|
|||
if (ret == -1) |
|||
fprintf(stderr, "pseudonative_handler: sometimes everything goes wrong\n"); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
void set_ld_lib_path() |
|||
{ |
|||
FILE *f = fopen("/etc/ld.so.conf", "r"); |
|||
char ld_lib_path[1024] = "/lib"; |
|||
int written = 4, len, i; |
|||
char line[1024], *l; |
|||
glob_t globbuf; |
|||
|
|||
l = getenv("LD_LIBRARY_PATH_PSEUDONATIVE_BACKUP"); |
|||
if (l) { |
|||
l = strdup(l); |
|||
l = strtok(l, ":"); |
|||
while ( l ) { |
|||
if ( strcmp(l, LIBDIR) && written < 1024) |
|||
written += snprintf(ld_lib_path+written, 1024-written, ":%s", l); |
|||
l = strtok(0, ":"); |
|||
} |
|||
unsetenv("LD_LIBRARY_PATH_PSEUDONATIVE_BACKUP"); |
|||
} |
|||
|
|||
if (f) { |
|||
while ( (l=fgets(line, 1024, f)) ) { |
|||
while ( *l == ' ' || *l == '\t' || *l == '\n' ) l++; |
|||
if ( *l == '#' || !*l ) continue; |
|||
|
|||
len = strcspn(l, "\t\n "); |
|||
if (len) { |
|||
l[len] = 0; |
|||
glob(l, GLOB_ONLYDIR, 0, &globbuf); |
|||
for (i=0; i<globbuf.gl_pathc && written < 1024; i++) |
|||
written += snprintf(ld_lib_path+written, 1024-written, ":%s", globbuf.gl_pathv[i]); |
|||
globfree (&globbuf); |
|||
} |
|||
} |
|||
fclose(f); |
|||
} |
|||
|
|||
if (config_debug) |
|||
fprintf(stderr, "pseudonative_handler: setting LD_LIBRARY_PATH: %s\n", ld_lib_path); |
|||
|
|||
setenv("LD_LIBRARY_PATH", ld_lib_path, 1); |
|||
} |
|||
|
|||
void write_log(char *type, char **argv) |
|||
{ |
|||
int written = 0; |
|||
char line[120] = ""; |
|||
FILE *f; |
|||
|
|||
if ( (f = fopen("/var/adm/rock-debug/pseudonative.log", "a")) ) { |
|||
written += snprintf(line+written, 1024-written, "%s: %s=%s", |
|||
type, getenv("ROCK_PKG"), getenv("ROCK_XPKG")); |
|||
while (*argv && written < 120) |
|||
written += snprintf(line+written, 120-written, " %s", *(argv++)); |
|||
strcpy(line+100, " .."); |
|||
fprintf(f, "%s\n", line); |
|||
fclose(f); |
|||
} |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
char *cmd, *mycmd, *t; |
|||
|
|||
while ( *argv[1] == '-' && argc > 1 ) { |
|||
if ( !strcmp(argv[1], "-d") ) config_debug = 1; |
|||
else if ( !strcmp(argv[1], "-r") ) config_remote = 1; |
|||
else { |
|||
fprintf(stderr, "pseudonative_handler: unknown option %s.\n", argv[1]); |
|||
return -1; |
|||
} |
|||
argv++; argc--; |
|||
} |
|||
|
|||
if (argc < 2) { |
|||
fprintf(stderr, "pseudonative_handler: arguments missing.\n"); |
|||
return -1; |
|||
} |
|||
|
|||
cmd = basename(argv[1]); |
|||
mycmd = malloc(BINDIR_SIZE+strlen(cmd)+10); |
|||
|
|||
t = getenv("LD_LIBRARY_PATH"); |
|||
if ( t && strcmp(t, LIBDIR) ) |
|||
setenv("LD_LIBRARY_PATH_PSEUDONATIVE_BACKUP", t, 1); |
|||
setenv("LD_LIBRARY_PATH", LIBDIR, 1); |
|||
|
|||
/* The target ld.so.cache would confuse bins for the build host. So |
|||
* we unlink it here and generate a LD_LIBRARY_PATH from ld.so.conf |
|||
* for bins executed on the remote machine. */ |
|||
unlink("/etc/ld.so.cache"); |
|||
|
|||
sprintf(mycmd, "%s/%s", BINDIR_1, cmd); |
|||
if ( !access(mycmd, X_OK) && !config_remote ) { |
|||
if (config_debug) |
|||
fprintf(stderr, "pseudonative_handler: local: %s\n", mycmd); |
|||
argv[1] = mycmd; |
|||
write_log("local", argv+1); |
|||
execv(mycmd, argv+1); |
|||
goto goterror; |
|||
} |
|||
|
|||
sprintf(mycmd, "%s/%s", BINDIR_2, cmd); |
|||
if ( !access(mycmd, X_OK) && !config_remote ) { |
|||
if (config_debug) |
|||
fprintf(stderr, "pseudonative_handler: local: %s\n", mycmd); |
|||
argv[1] = mycmd; |
|||
write_log("local", argv+1); |
|||
execv(mycmd, argv+1); |
|||
goto goterror; |
|||
} |
|||
|
|||
/* FIXME: CMD_ENABLE0 doesn't work correctly yet (see pseudonative_daemon.c). |
|||
* So we close fd0 explicitely for some programs here. */ |
|||
#if 0 |
|||
if ( !strcmp(cmd, "tput") ) { close(0); open("/dev/null", O_RDONLY); } |
|||
#endif |
|||
|
|||
set_ld_lib_path(); |
|||
if (config_debug) |
|||
fprintf(stderr, "pseudonative_handler: remote: %s\n", argv[1]); |
|||
write_log("remote", argv+1); |
|||
return exec_remote(argv+1); |
|||
|
|||
goterror: |
|||
fprintf(stderr, "pseudonative_handler: error calling '%s': %s\n", mycmd, strerror(errno)); |
|||
return -1; |
|||
} |
|||
|
|||