/* This file is in the public domain. */ #include #include #include #include #include #include #include #include extern const char *__progname; #include "errf.h" #include "util.h" #include "panic.h" #include "config.h" #include "nested.h" #include "connshare.h" static const char *lock_fn; static int lock_fd = -1; static const char *server_path; static int server_fd; void share_auto(const char *rz, const char *lk) { int s; struct sockaddr_un *sun; int pl; pid_t kid; int cp[2]; char cflag; NESTED void setsun(void) { sun->sun_family = AF_LOCAL; sun->sun_len = sizeof(*sun) - sizeof(sun->sun_path) + pl; bcopy(rz,&sun->sun_path[0],pl); } NESTED void getsocket(void) { s = socket(AF_LOCAL,SOCK_STREAM,0); if (s < 0) { fprintf(errf,"%s: can't create sharing socket: %s\n",__progname,strerror(errno)); exit(1); } } server_path = rz; pl = strlen(rz); sun = malloc(sizeof(*sun)-sizeof(sun->sun_path)+pl); lock_fn = lk; lock_fd = open(lk,O_RDONLY|O_CREAT,0666); if (lock_fd < 0) { fprintf(errf,"%s: can't open sharing lock file %s: %s\n",__progname,lk,strerror(errno)); exit(1); } if (flock(lock_fd,LOCK_EX) < 0) { fprintf(errf,"%s: can't lock sharing lock file %s: %s\n",__progname,lk,strerror(errno)); exit(1); } getsocket(); setsun(); if (connect(s,(void *)sun,sun->sun_len) >= 0) { close(lock_fd); share_client_auto(s); config_set_bool("share-client",1); config_set_bool("share-server",0); if (VERB(SHARECONN_C)) verb(SHARECONN_C,"C: connection to %s succeeded, server already running\n",rz); return; } switch (errno) { case ECONNREFUSED: case ENOENT: if (VERB(SHARECONN_C)) verb(SHARECONN_C,"C: connection to %s failed [%s]\n",rz,strerror(errno)); break; default: fprintf(errf,"%s: can't connect sharing socket: %s\n",__progname,strerror(errno)); exit(1); break; } close(s); if (unlink(rz) < 0) { switch (errno) { case ENOENT: break; default: fprintf(errf,"%s: warning: can't unlink sharing socket %s: %s\n",__progname,rz,strerror(errno)); break; } } getsocket(); setsun(); if (bind(s,(void *)sun,sun->sun_len) < 0) { fprintf(errf,"%s: can't create sharing socket: %s\n",__progname,strerror(errno)); exit(1); } if (listen(s,10) < 0) { fprintf(errf,"%s: can't listen to sharing socket: %s\n",__progname,strerror(errno)); exit(1); } if (VERB(SHARECONN_C) || VERB(SHARECONN_S)) pverb(VERBOSE_SHARECONN_C|VERBOSE_SHARECONN_S,"starting sharing server\n"); if (pipe(&cp[0]) < 0) { fprintf(errf,"%s: can't create sharing admin pipe: %s\n",__progname,strerror(errno)); exit(1); } fflush(0); kid = moussh_fork(); if (kid < 0) { fprintf(errf,"%s: can't fork sharing server\n",__progname); exit(1); } if (kid == 0) { flock(lock_fd,LOCK_UN); close(cp[0]); server_fd = s; share_server_auto(s,cp[1],config_int("auto-share-timeout")); config_set_bool("share-client",0); config_set_bool("share-server",1); config_set_bool("do-nothing",1); config_set_bool("just-die",0); config_set_bool("no-input",1); config_set_bool("request-pty",0); config_nofwd(); if (VERB(SHARECONN_S)) verb(SHARECONN_S,"S: sharing server starting\n"); return; } close(lock_fd); lock_fd = -1; close(s); close(cp[1]); cflag = 1; if ((read(cp[0],&cflag,1) != 1) || (cflag != 0)) exit(cflag); close(cp[0]); getsocket(); setsun(); if (connect(s,(void *)sun,sun->sun_len) < 0) { fprintf(errf,"%s: *still* can't connect sharing socket %s: %s\n",__progname,rz,strerror(errno)); exit(1); } if (VERB(SHARECONN_C)) verb(SHARECONN_C,"C: connected to new sharing server\n"); share_client_auto(s); config_set_bool("share-client",1); config_set_bool("share-server",0); } void share_auto_timed_out(const char *why) { struct pollfd pfd; int rv; if (lock_fd < 0) panic("missing lock_fd"); if (VERB(SHARECONN_S)) verb(SHARECONN_S,"S: exiting: %s\n",why); if (flock(lock_fd,LOCK_EX) < 0) { fprintf(errf,"%s: can't lock sharing lock file %s: %s\n",__progname,lock_fn,strerror(errno)); exit(1); } pfd.fd = server_fd; pfd.events = POLLIN | POLLRDNORM; rv = poll(&pfd,1,0); if (rv < 0) { fprintf(errf,"%s: poll: %s\n",__progname,strerror(errno)); exit(1); } if (rv == 0) { unlink(server_path); exit(0); } if (rv != 1) panic("impossible poll() return"); flock(lock_fd,LOCK_UN); }