|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2013 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef ATTACH_H
|
|
Packit |
8f70b4 |
#define ATTACH_H
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h> // for mkdir()
|
|
Packit |
8f70b4 |
#include <stdio.h>
|
|
Packit |
8f70b4 |
#include <stdlib.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <locale.h>
|
|
Packit |
8f70b4 |
#include <ctype.h>
|
|
Packit |
8f70b4 |
#include <sys/un.h>
|
|
Packit |
8f70b4 |
#if HAVE_SYS_SOCKET_H
|
|
Packit |
8f70b4 |
# include <sys/socket.h>
|
|
Packit |
8f70b4 |
#elif HAVE_WS2TCPIP_H
|
|
Packit |
8f70b4 |
# include <ws2tcpip.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "SMTask.h"
|
|
Packit |
8f70b4 |
#include "Error.h"
|
|
Packit |
8f70b4 |
#include "SignalHook.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "passfd.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef SUN_LEN
|
|
Packit |
8f70b4 |
#define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class AcceptTermFD : public SMTask
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int sock;
|
|
Packit |
8f70b4 |
int a_sock;
|
|
Packit |
8f70b4 |
int recv_i;
|
|
Packit |
8f70b4 |
int fds[3];
|
|
Packit |
8f70b4 |
bool accepted;
|
|
Packit |
8f70b4 |
bool detached;
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
AcceptTermFD() : sock(-1), a_sock(-1), recv_i(0), accepted(false), detached(false) {
|
|
Packit |
8f70b4 |
do_listen();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
~AcceptTermFD() {
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
close(fds[i]);
|
|
Packit |
8f70b4 |
if(sock!=-1) {
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
unlink(get_sock_path());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(a_sock!=-1)
|
|
Packit |
8f70b4 |
close(a_sock);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Do() {
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(detached)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(accepted) {
|
|
Packit |
8f70b4 |
char buf;
|
|
Packit |
8f70b4 |
int res=read(a_sock,&buf,1);
|
|
Packit |
8f70b4 |
if(res==-1 && E_RETRY(errno)) {
|
|
Packit |
8f70b4 |
Block(a_sock,POLLIN);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res<=0) {
|
|
Packit |
8f70b4 |
detached=true;
|
|
Packit |
8f70b4 |
close(a_sock);
|
|
Packit |
8f70b4 |
a_sock=-1;
|
|
Packit |
8f70b4 |
raise(SIGHUP);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(a_sock==-1) {
|
|
Packit |
8f70b4 |
if(sock==-1)
|
|
Packit |
8f70b4 |
do_listen();
|
|
Packit |
8f70b4 |
if(sock==-1) {
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!Ready(sock,POLLIN)) {
|
|
Packit |
8f70b4 |
Block(sock,POLLIN);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
struct sockaddr_un sun_addr;
|
|
Packit |
8f70b4 |
socklen_t sa_len=sizeof(sun_addr);
|
|
Packit |
8f70b4 |
a_sock=accept(sock,(sockaddr*)&sun_addr,&sa_len);
|
|
Packit |
8f70b4 |
if(a_sock==-1 && E_RETRY(errno)) {
|
|
Packit |
8f70b4 |
Block(sock,POLLIN);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(a_sock==-1) {
|
|
Packit |
8f70b4 |
perror("accept");
|
|
Packit |
8f70b4 |
do_listen();
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
sock=-1;
|
|
Packit |
8f70b4 |
int fl=fcntl(a_sock,F_GETFL);
|
|
Packit |
8f70b4 |
fcntl(a_sock,F_SETFL,fl|O_NONBLOCK);
|
|
Packit |
8f70b4 |
fcntl(a_sock,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
while(recv_i<=2) {
|
|
Packit |
8f70b4 |
int fd=recvfd(a_sock,0);
|
|
Packit |
8f70b4 |
if(fd==-1 && E_RETRY(errno)) {
|
|
Packit |
8f70b4 |
Block(a_sock,POLLIN);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
perror("recvfd");
|
|
Packit |
8f70b4 |
do_listen();
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
fcntl(fd,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
fds[recv_i]=fd;
|
|
Packit |
8f70b4 |
++recv_i;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
printf(_("[%u] Attached to terminal %s. %s\n"),(unsigned)getpid(),ttyname(fds[1]),now.IsoDateTime());
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
dup2(fds[i],i);
|
|
Packit |
8f70b4 |
if(fds[i]>=recv_i)
|
|
Packit |
8f70b4 |
close(fds[i]);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
sock=-1;
|
|
Packit |
8f70b4 |
unlink(get_sock_path());
|
|
Packit |
8f70b4 |
accepted=true;
|
|
Packit |
8f70b4 |
printf(_("[%u] Attached to terminal.\n"),(unsigned)getpid());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static xstring& get_sock_path(int pid=0) {
|
|
Packit |
8f70b4 |
if(!pid)
|
|
Packit |
8f70b4 |
pid=getpid();
|
|
Packit |
8f70b4 |
const char *home=get_lftp_data_dir();
|
|
Packit |
8f70b4 |
mkdir(xstring::format("%s/bg",home),0700);
|
|
Packit |
8f70b4 |
return xstring::format("%s/bg/%s-%d",home,get_nodename(),pid);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void do_listen() {
|
|
Packit |
8f70b4 |
const char *path=get_sock_path();
|
|
Packit |
8f70b4 |
unlink(path);
|
|
Packit |
8f70b4 |
if(sock>=0)
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
if(a_sock>=0) {
|
|
Packit |
8f70b4 |
close(a_sock);
|
|
Packit |
8f70b4 |
a_sock=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
close(fds[i]);
|
|
Packit |
8f70b4 |
recv_i=0;
|
|
Packit |
8f70b4 |
accepted=false;
|
|
Packit |
8f70b4 |
detached=false;
|
|
Packit |
8f70b4 |
sock=socket(AF_UNIX,SOCK_STREAM,0);
|
|
Packit |
8f70b4 |
if(sock!=-1) {
|
|
Packit |
8f70b4 |
int fl=fcntl(sock,F_GETFL);
|
|
Packit |
8f70b4 |
fcntl(sock,F_SETFL,fl|O_NONBLOCK);
|
|
Packit |
8f70b4 |
fcntl(sock,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
struct sockaddr_un sun_addr;
|
|
Packit |
8f70b4 |
memset(&sun_addr,0,sizeof(sun_addr));
|
|
Packit |
8f70b4 |
sun_addr.sun_family=AF_UNIX;
|
|
Packit |
8f70b4 |
strncpy(sun_addr.sun_path,path,sizeof(sun_addr.sun_path));
|
|
Packit |
8f70b4 |
if(bind(sock,(sockaddr*)&sun_addr,SUN_LEN(&sun_addr))==-1) {
|
|
Packit |
8f70b4 |
perror("bind");
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
sock=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(sock>=0)
|
|
Packit |
8f70b4 |
listen(sock,1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool Accepted() { return accepted; }
|
|
Packit |
8f70b4 |
void Detach() { do_listen(); }
|
|
Packit |
8f70b4 |
bool Detached() { return detached; }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class SendTermFD : public SMTask
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static pid_t pass_pid;
|
|
Packit |
8f70b4 |
static void pass_sig(int s) {
|
|
Packit |
8f70b4 |
kill(pass_pid,s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Ref<Error> error;
|
|
Packit |
8f70b4 |
pid_t pid;
|
|
Packit |
8f70b4 |
int sock;
|
|
Packit |
8f70b4 |
bool connected;
|
|
Packit |
8f70b4 |
bool sent;
|
|
Packit |
8f70b4 |
int send_i;
|
|
Packit |
8f70b4 |
bool detached;
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
SendTermFD(pid_t p) : pid(p), sock(-1), connected(false), sent(false), send_i(0), detached(false) {}
|
|
Packit |
8f70b4 |
~SendTermFD() {
|
|
Packit |
8f70b4 |
if(sock>=0)
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Do() {
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(error || detached)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(sent) {
|
|
Packit |
8f70b4 |
char buf;
|
|
Packit |
8f70b4 |
int res=read(sock,&buf,1);
|
|
Packit |
8f70b4 |
if(res==-1 && E_RETRY(errno)) {
|
|
Packit |
8f70b4 |
Block(sock,POLLIN);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res<=0) {
|
|
Packit |
8f70b4 |
detached=true;
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
sock=-1;
|
|
Packit |
8f70b4 |
SignalHook::DoCount(SIGINT);
|
|
Packit |
8f70b4 |
SignalHook::Restore(SIGQUIT);
|
|
Packit |
8f70b4 |
SignalHook::DoCount(SIGTSTP);
|
|
Packit |
8f70b4 |
SignalHook::Restore(SIGWINCH);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(sock==-1) {
|
|
Packit |
8f70b4 |
sock=socket(AF_UNIX,SOCK_STREAM,0);
|
|
Packit |
8f70b4 |
if(sock==-1) {
|
|
Packit |
8f70b4 |
if(NonFatalError(errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
error=Error::Fatal(xstring::format("socket(): %s",strerror(errno)));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int fl=fcntl(sock,F_GETFL);
|
|
Packit |
8f70b4 |
fcntl(sock,F_SETFL,fl|O_NONBLOCK);
|
|
Packit |
8f70b4 |
fcntl(sock,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
connected=false;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!connected) {
|
|
Packit |
8f70b4 |
struct sockaddr_un sun_addr;
|
|
Packit |
8f70b4 |
memset(&sun_addr,0,sizeof(sun_addr));
|
|
Packit |
8f70b4 |
sun_addr.sun_family=AF_UNIX;
|
|
Packit |
8f70b4 |
const char *path=AcceptTermFD::get_sock_path(pid);
|
|
Packit |
8f70b4 |
strncpy(sun_addr.sun_path,path,sizeof(sun_addr.sun_path));
|
|
Packit |
8f70b4 |
int res=connect(sock,(sockaddr*)&sun_addr,SUN_LEN(&sun_addr));
|
|
Packit |
8f70b4 |
if(res==-1 && !NonFatalError(errno)) {
|
|
Packit |
8f70b4 |
error=Error::Fatal(xstring::format("connect(%s): %s",path,strerror(errno)));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res==-1) {
|
|
Packit |
8f70b4 |
Block(sock,POLLOUT);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
connected=true;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
while(send_i<=2) {
|
|
Packit |
8f70b4 |
if(sendfd(sock,send_i)<0) {
|
|
Packit |
8f70b4 |
if(NonFatalError(errno)) {
|
|
Packit |
8f70b4 |
Block(sock,POLLOUT);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
error=Error::Fatal(xstring::format("sendfd: %s",strerror(errno)));
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
sock=-1;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
++send_i;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
sent=true;
|
|
Packit |
8f70b4 |
pass_pid=pid;
|
|
Packit |
8f70b4 |
if(isatty(0)) {
|
|
Packit |
8f70b4 |
SignalHook::Handle(SIGINT,pass_sig);
|
|
Packit |
8f70b4 |
SignalHook::Handle(SIGQUIT,pass_sig);
|
|
Packit |
8f70b4 |
SignalHook::Handle(SIGTSTP,pass_sig);
|
|
Packit |
8f70b4 |
SignalHook::Handle(SIGWINCH,pass_sig);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool Done() { return error || detached; }
|
|
Packit |
8f70b4 |
bool Failed() { return error; }
|
|
Packit |
8f70b4 |
const char *ErrorText() { return error->Text(); }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
#endif
|