/* $Id$ */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CONNECT_RETRY_MSEC 100 static long opt_start_timeout=60; static int opt_port; static int opt_syslog; static int opt_stderr; static const char *opt_lock; /* /usr/include/glib-2.0/glib/gmacros.h */ #ifndef G_GNUC_PRINTF #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) #define G_GNUC_PRINTF( format_idx, arg_idx ) \ __attribute__((__format__ (__printf__, format_idx, arg_idx))) #else /* !__GNUC__ */ #define G_GNUC_PRINTF( format_idx, arg_idx ) #endif /* !__GNUC__ */ #endif /* !G_GNUC_PRINTF */ /* /usr/include/glib-2.0/glib/gmacros.h */ #ifndef G_GNUC_NORETURN #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) #define G_GNUC_NORETURN \ __attribute__((__noreturn__)) #else /* !__GNUC__ */ #define G_GNUC_NORETURN #endif /* !__GNUC__ */ #endif /* !G_GNUC_NORETURN */ /* /usr/include/glib-2.0/glib/gmacros.h */ /* Count the number of elements in an array. The array must be defined * as such; using this with a dynamically allocated array will give * incorrect results. */ #define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) static const char *program_name; static void fatal(const char *fmt,...) G_GNUC_PRINTF(1,2) G_GNUC_NORETURN; static void fatal(const char *fmt,...) { int use_syslog=opt_syslog,use_stderr=opt_stderr; va_list ap; char *string; const char *const error_error="Error printing error message"; if (!use_syslog && !use_stderr) use_stderr=1; va_start(ap,fmt); if (-1==vasprintf(&string,fmt,ap)) { if (fmt==error_error) exit(EXIT_FAILURE); fatal(error_error); } if (use_stderr) fprintf(stderr,"%s: %s!\n",program_name,string); if (use_syslog) { openlog(program_name,LOG_PID,LOG_DAEMON); syslog(LOG_DAEMON|LOG_ERR,"%s!",string); closelog(); } va_end(ap); exit(EXIT_FAILURE); } static void usage(void) { fprintf(stderr,"\ Syntax: %s [{-T|--start-timeout} ]\n\ {-p|--port} \n\ \n\ Error messages out to stderr by default, -S|--syslog omits stderr output,\n\ both -S|--syslog and -e|--stderr output the errors by both methods.\n\ \n",program_name); exit(EXIT_FAILURE); } static const struct option longopts[]={ {"start-timeout",1,0,'T'}, {"syslog" ,0,0,'S'}, {"stderr" ,0,0,'e'}, {"lock" ,1,0,'l'}, {"port" ,1,0,'p'}, {NULL ,0,0,0 }, }; static int connect_try(void) { int fdtcp; struct sockaddr_in sockaddr_tcp; if (-1==(fdtcp=socket(PF_INET,SOCK_STREAM,0))) fatal("socket(PF_INET,SOCK_STREAM,0)=%d: %m",fdtcp); memset(&sockaddr_tcp,0,sizeof(sockaddr_tcp)); sockaddr_tcp.sin_family=AF_INET; sockaddr_tcp.sin_addr.s_addr=htonl(INADDR_LOOPBACK); sockaddr_tcp.sin_port=htons(opt_port); if (connect(fdtcp,(const struct sockaddr *)&sockaddr_tcp,sizeof(sockaddr_tcp))) { if (errno==ECONNREFUSED) return -1; fatal("connect(TCP socket,127.0.0.1:%d): %m",opt_port); } return fdtcp; } static void session_transfer( const char *conn0_name,int conn0_fdin,int conn0_fdout, const char *conn1_name,int conn1_fdin,int conn1_fdout) G_GNUC_NORETURN; static void session_transfer( const char *conn0_name,int conn0_fdin,int conn0_fdout, const char *conn1_name,int conn1_fdin,int conn1_fdout) { struct pollfd pollfdi[2]; int pollfdo[2]; const char *pollfdi_name[2]; int fdi,fdo; pollfdi[0].fd=conn0_fdin; pollfdi[0].events=POLLIN; pollfdi[1].fd=conn1_fdin; pollfdi[1].events=POLLIN; pollfdo[0]=conn0_fdout; pollfdo[1]=conn1_fdout; pollfdi_name[0]=conn0_name; pollfdi_name[1]=conn1_name; for (;;) { for (fdi=0;fdi=G_N_ELEMENTS(pollfdi)) exit(EXIT_SUCCESS); if (0>=poll(pollfdi,G_N_ELEMENTS(pollfdi),-1)) fatal("poll(%s socket,%s socket): %m",pollfdi_name[0],pollfdi_name[1]); for (fdi=0;fdi=LONG_MAX || (endptr && *endptr)) fatal("Invalid -T|--start-timeout values: %s",optarg); opt_start_timeout=l; break; case 'S': /* -S|--syslog */ opt_syslog=1; break; case 'e': /* -e|--stderr */ opt_stderr=1; break; case 'l': /* -l|--lock */ opt_lock=optarg; case 'p': /* -p|--port */ l=strtol(optarg,&endptr,0); if (l<=0 || l>=0x10000 || (endptr && *endptr)) fatal("Invalid -p|--port value: %s",optarg); opt_port=l; break; default: if (optc!='h') fatal("Error parsing commandline!"); usage(); break; } if (!opt_port) fatal("-p|--port is a required argument!"); if (optind>=argc) fatal(" is a required argument!"); if (optind+1 needs quoting?"); command=argv[optind]; lock_create(); session_try(); system_checked(command); for (retry=0;retry*CONNECT_RETRY_MSEC/1000