mirror of the now-defunct rocklinux.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

423 lines
9.8 KiB

  1. #include <stdio.h>
  2. #include <libgen.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <stdlib.h>
  7. #include <stdint.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <sys/socket.h>
  11. #include <sys/time.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <fcntl.h>
  15. #include <glob.h>
  16. #include <signal.h>
  17. extern char **environ;
  18. #define LIBDIR "/ROCK/tools.cross/pseudonative.lib"
  19. #define BINDIR_1 "/ROCK/tools.cross/pseudonative.bin"
  20. #define BINDIR_2 "/ROCK/tools.cross/bin"
  21. #define BINDIR_SIZE 100
  22. #define TCPPORT 28336
  23. #define CMD_EXEC 1
  24. #define CMD_ADDARG 2
  25. #define CMD_ADDENV 3
  26. #define CMD_CHDIR 4
  27. #define CMD_CHROOT 5
  28. #define CMD_EXIT 6
  29. #define CMD_BUILDID 7
  30. #define CMD_WRITE0 1000
  31. #define CMD_CLOSE0 2000
  32. #define CMD_ENABLE0 3000
  33. int config_debug = 0;
  34. int config_remote = 0;
  35. struct pn_pkg {
  36. uint32_t len;
  37. uint32_t type;
  38. char data[];
  39. };
  40. int conn_open(const char *peer)
  41. {
  42. struct sockaddr_in sin;
  43. int conn;
  44. sin.sin_family = PF_INET;
  45. sin.sin_port = htons(TCPPORT);
  46. if ( !inet_aton(peer, &sin.sin_addr) ) {
  47. fprintf(stderr, "pseudonative_handler: can't parse address '%s'\n", peer);
  48. exit(-1);
  49. }
  50. conn = socket(PF_INET, SOCK_STREAM, 0);
  51. if (conn < 0) {
  52. fprintf(stderr, "pseudonative_handler: can't create socket: %s\n", strerror(errno));
  53. exit(-1);
  54. }
  55. if (connect(conn, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  56. fprintf(stderr, "pseudonative_handler: can't connect to remote host: %s\n", strerror(errno));
  57. exit(-1);
  58. }
  59. return conn;
  60. }
  61. void conn_send(int conn, int len, int type, char *data)
  62. {
  63. struct pn_pkg *p = malloc( sizeof(struct pn_pkg) + len );
  64. int i, rc;
  65. p->len = htonl(len);
  66. p->type = htonl(type);
  67. memcpy(p->data, data, len);
  68. len += sizeof(struct pn_pkg);
  69. for (i = 0; i < len; i += rc) {
  70. rc = write(conn, (char*)p + i, len - i);
  71. if ( rc <= 0 ) {
  72. if ( errno == ECONNRESET && type == CMD_CLOSE0 ) break;
  73. fprintf(stderr, "pseudonative_handler: network write error: %s\n", strerror(errno));
  74. exit(-1);
  75. }
  76. }
  77. free(p);
  78. }
  79. int conn_read(int conn, char *buf, int len, int nonblock)
  80. {
  81. int f = -1;
  82. if ( nonblock ) {
  83. f = fcntl(conn, F_GETFL, 0);
  84. fcntl(conn, F_SETFL, f | O_NONBLOCK);
  85. }
  86. while (len) {
  87. int rc = read(conn, buf, len);
  88. if ( rc < 0 ) {
  89. if ( errno == EAGAIN ) break;
  90. fprintf(stderr, "pseudonative_handler: network read error: %s\n", strerror(errno));
  91. exit(-1);
  92. }
  93. if ( rc == 0 ) {
  94. fprintf(stderr, "pseudonative_handler: connection closed by peer\n");
  95. exit(-1);
  96. }
  97. if ( f != -1 )
  98. fcntl(conn, F_SETFL, f);
  99. len -= rc; buf += rc; f = -1;
  100. }
  101. if ( f != -1 )
  102. fcntl(conn, F_SETFL, f);
  103. return len;
  104. }
  105. struct pn_pkg *conn_recv(int conn)
  106. {
  107. struct pn_pkg *p = malloc( sizeof(struct pn_pkg) );
  108. if ( conn_read(conn, (char*)p, 8, 1) ) {
  109. free(p);
  110. return 0;
  111. }
  112. p->len = ntohl(p->len);
  113. p->type = ntohl(p->type);
  114. p = realloc(p, sizeof(struct pn_pkg) + p->len);
  115. conn_read(conn, p->data, p->len, 0);
  116. return p;
  117. }
  118. int exec_remote(char ** argv)
  119. {
  120. char buf[1024], *txt;
  121. int ret = -1, open_0 = 1;
  122. int enable_0 = 0;
  123. int f, i, conn, rc;
  124. struct timeval tv;
  125. struct pn_pkg *p;
  126. fd_set rfds;
  127. /* connect */
  128. txt = getenv("ROCKCFG_PSEUDONATIVE_NATIVEHOST");
  129. if ( txt && *txt ) {
  130. conn = conn_open(txt);
  131. } else {
  132. fprintf(stderr, "pseudonative_handler: no native host configured\n");
  133. exit(-1);
  134. }
  135. /* send build id */
  136. txt = getenv("ROCKCFG_ID");
  137. if ( txt && *txt )
  138. conn_send(conn, strlen(txt)+1, CMD_BUILDID, txt);
  139. /* mount and chroot */
  140. txt = getenv("ROCKCFG_PSEUDONATIVE_NFSROOT");
  141. if ( txt && *txt )
  142. conn_send(conn, strlen(txt)+1, CMD_CHROOT, txt);
  143. /* current directory */
  144. if ( getcwd(buf, 1024) )
  145. conn_send(conn, strlen(buf)+1, CMD_CHDIR, buf);
  146. /* send environment */
  147. for (i=0; environ[i]; i++)
  148. conn_send(conn, strlen(environ[i])+1, CMD_ADDENV, environ[i]);
  149. /* send arguments */
  150. for (i=0; argv[i]; i++)
  151. conn_send(conn, strlen(argv[i])+1, CMD_ADDARG, argv[i]);
  152. /* execute command */
  153. conn_send(conn, strlen(argv[0])+1, CMD_EXEC, argv[0]);
  154. /* we pass sigpipe's to peer */
  155. signal(SIGPIPE, SIG_IGN);
  156. while (1)
  157. {
  158. FD_ZERO(&rfds);
  159. if ( open_0 && enable_0 ) FD_SET(0, &rfds);
  160. FD_SET(conn, &rfds);
  161. nextselect:
  162. tv.tv_sec = 1;
  163. tv.tv_usec = 0;
  164. rc = select(conn+1, &rfds, 0, 0, &tv);
  165. if ( rc < 0 ) {
  166. if ( errno == EINTR ) goto nextselect;
  167. fprintf(stderr, "pseudonative_handler: select error: %s\n", strerror(errno));
  168. exit(-1);
  169. }
  170. nextread:
  171. if ( (p = conn_recv(conn)) != 0 ) {
  172. char *d = p->data;
  173. switch (p->type) {
  174. case CMD_WRITE0+1:
  175. while ( p->len ) {
  176. rc = write(1, d, p->len);
  177. if ( rc <= 0 ) {
  178. if ( errno == EPIPE ) {
  179. conn_send(conn, 0, CMD_CLOSE0+1, 0);
  180. break;
  181. }
  182. fprintf(stderr, "pseudonative_handler: write error on fd1: %s\n", strerror(errno));
  183. exit(-1);
  184. }
  185. d += rc; p->len -= rc;
  186. }
  187. break;
  188. case CMD_WRITE0+2:
  189. while ( p->len ) {
  190. rc = write(2, d, p->len);
  191. if ( rc <= 0 ) {
  192. if ( errno == EPIPE ) {
  193. conn_send(conn, 0, CMD_CLOSE0+2, 0);
  194. break;
  195. }
  196. fprintf(stderr, "pseudonative_handler: write error on fd2: %s\n", strerror(errno));
  197. exit(-1);
  198. }
  199. d += rc; p->len -= rc;
  200. }
  201. break;
  202. case CMD_CLOSE0:
  203. close(0);
  204. open_0 = 0;
  205. break;
  206. case CMD_CLOSE0+1:
  207. close(1);
  208. break;
  209. case CMD_CLOSE0+2:
  210. close(2);
  211. break;
  212. case CMD_ENABLE0:
  213. enable_0 = 1;
  214. break;
  215. case CMD_EXIT:
  216. ret = (unsigned char)p->data[0];
  217. free(p);
  218. goto finish;
  219. }
  220. free(p);
  221. goto nextread;
  222. }
  223. if( open_0 && enable_0 )
  224. {
  225. f = fcntl(0, F_GETFL, 0);
  226. fcntl(0, F_SETFL, f | O_NONBLOCK);
  227. rc = read(0, buf, 512);
  228. fcntl(0, F_SETFL, f);
  229. if ( rc > 0 ) {
  230. conn_send(conn, rc, CMD_WRITE0, buf);
  231. goto nextread;
  232. } else if (rc == 0) {
  233. conn_send(conn, 0, CMD_CLOSE0, 0);
  234. open_0 = 0;
  235. } else if ( errno != EAGAIN ) {
  236. perror("Error on read from f2:");
  237. }
  238. }
  239. }
  240. finish:
  241. close(conn);
  242. if (ret == -1)
  243. fprintf(stderr, "pseudonative_handler: sometimes everything goes wrong\n");
  244. return ret;
  245. }
  246. void set_ld_lib_path()
  247. {
  248. FILE *f = fopen("/etc/ld.so.conf", "r");
  249. char ld_lib_path[1024] = "/lib";
  250. int written = 4, len, i;
  251. char line[1024], *l;
  252. glob_t globbuf;
  253. l = getenv("LD_LIBRARY_PATH_PSEUDONATIVE_BACKUP");
  254. if (l) {
  255. l = strdup(l);
  256. l = strtok(l, ":");
  257. while ( l ) {
  258. if ( strcmp(l, LIBDIR) && written < 1024)
  259. written += snprintf(ld_lib_path+written, 1024-written, ":%s", l);
  260. l = strtok(0, ":");
  261. }
  262. unsetenv("LD_LIBRARY_PATH_PSEUDONATIVE_BACKUP");
  263. }
  264. if (f) {
  265. while ( (l=fgets(line, 1024, f)) ) {
  266. while ( *l == ' ' || *l == '\t' || *l == '\n' ) l++;
  267. if ( *l == '#' || !*l ) continue;
  268. len = strcspn(l, "\t\n ");
  269. if (len) {
  270. l[len] = 0;
  271. glob(l, GLOB_ONLYDIR, 0, &globbuf);
  272. for (i=0; i<globbuf.gl_pathc && written < 1024; i++)
  273. written += snprintf(ld_lib_path+written, 1024-written, ":%s", globbuf.gl_pathv[i]);
  274. globfree (&globbuf);
  275. }
  276. }
  277. fclose(f);
  278. }
  279. if (config_debug)
  280. fprintf(stderr, "pseudonative_handler: setting LD_LIBRARY_PATH: %s\n", ld_lib_path);
  281. setenv("LD_LIBRARY_PATH", ld_lib_path, 1);
  282. }
  283. void write_log(char *type, char **argv)
  284. {
  285. int written = 0;
  286. char line[120] = "";
  287. FILE *f;
  288. if ( (f = fopen("/var/adm/rock-debug/pseudonative.log", "a")) ) {
  289. written += snprintf(line+written, 1024-written, "%s: %s=%s",
  290. type, getenv("ROCK_PKG"), getenv("ROCK_XPKG"));
  291. while (*argv && written < 120)
  292. written += snprintf(line+written, 120-written, " %s", *(argv++));
  293. strcpy(line+100, " ..");
  294. fprintf(f, "%s\n", line);
  295. fclose(f);
  296. }
  297. }
  298. int main(int argc, char **argv)
  299. {
  300. char *cmd, *mycmd, *t;
  301. while ( *argv[1] == '-' && argc > 1 ) {
  302. if ( !strcmp(argv[1], "-d") ) config_debug = 1;
  303. else if ( !strcmp(argv[1], "-r") ) config_remote = 1;
  304. else {
  305. fprintf(stderr, "pseudonative_handler: unknown option %s.\n", argv[1]);
  306. return -1;
  307. }
  308. argv++; argc--;
  309. }
  310. if (argc < 2) {
  311. fprintf(stderr, "pseudonative_handler: arguments missing.\n");
  312. return -1;
  313. }
  314. cmd = basename(argv[1]);
  315. mycmd = malloc(BINDIR_SIZE+strlen(cmd)+10);
  316. t = getenv("LD_LIBRARY_PATH");
  317. if ( t && strcmp(t, LIBDIR) )
  318. setenv("LD_LIBRARY_PATH_PSEUDONATIVE_BACKUP", t, 1);
  319. setenv("LD_LIBRARY_PATH", LIBDIR, 1);
  320. /* The target ld.so.cache would confuse bins for the build host. So
  321. * we unlink it here and generate a LD_LIBRARY_PATH from ld.so.conf
  322. * for bins executed on the remote machine. */
  323. unlink("/etc/ld.so.cache");
  324. sprintf(mycmd, "%s/%s", BINDIR_1, cmd);
  325. if ( !access(mycmd, X_OK) && !config_remote ) {
  326. if (config_debug)
  327. fprintf(stderr, "pseudonative_handler: local: %s\n", mycmd);
  328. argv[1] = mycmd;
  329. write_log("local", argv+1);
  330. execv(mycmd, argv+1);
  331. goto goterror;
  332. }
  333. sprintf(mycmd, "%s/%s", BINDIR_2, cmd);
  334. if ( !access(mycmd, X_OK) && !config_remote ) {
  335. if (config_debug)
  336. fprintf(stderr, "pseudonative_handler: local: %s\n", mycmd);
  337. argv[1] = mycmd;
  338. write_log("local", argv+1);
  339. execv(mycmd, argv+1);
  340. goto goterror;
  341. }
  342. /* FIXME: CMD_ENABLE0 doesn't work correctly yet (see pseudonative_daemon.c).
  343. * So we close fd0 explicitely for some programs here. */
  344. #if 0
  345. if ( !strcmp(cmd, "tput") ) { close(0); open("/dev/null", O_RDONLY); }
  346. #endif
  347. set_ld_lib_path();
  348. if (config_debug)
  349. fprintf(stderr, "pseudonative_handler: remote: %s\n", argv[1]);
  350. write_log("remote", argv+1);
  351. return exec_remote(argv+1);
  352. goterror:
  353. fprintf(stderr, "pseudonative_handler: error calling '%s': %s\n", mycmd, strerror(errno));
  354. return -1;
  355. }