|
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 |
#include <config.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "modconfig.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h> // for mkdir()
|
|
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 |
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
#include "xmalloc.h"
|
|
Packit |
8f70b4 |
#include "alias.h"
|
|
Packit |
8f70b4 |
#include "CmdExec.h"
|
|
Packit |
8f70b4 |
#include "SignalHook.h"
|
|
Packit |
8f70b4 |
#include "GetPass.h"
|
|
Packit |
8f70b4 |
#include "History.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "DummyProto.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "LsCache.h"
|
|
Packit |
8f70b4 |
#include "IdNameCache.h"
|
|
Packit |
8f70b4 |
#include "LocalDir.h"
|
|
Packit |
8f70b4 |
#include "ConnectionSlot.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
#include "attach.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "configmake.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "lftp_rl.h"
|
|
Packit |
8f70b4 |
#include "complete.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
#include <glob.h>
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define top_exec CmdExec::top
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void hook_signals()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SignalHook::DoCount(SIGHUP);
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGTTOU);
|
|
Packit |
8f70b4 |
ProcWait::Signal(true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResDecl res_save_cwd_history
|
|
Packit |
8f70b4 |
("cmd:save-cwd-history","yes",ResMgr::BoolValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
ResDecl res_save_rl_history
|
|
Packit |
8f70b4 |
("cmd:save-rl-history","yes",ResMgr::BoolValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
ResDecl res_stifle_rl_history
|
|
Packit |
8f70b4 |
("cmd:stifle-rl-history","500",ResMgr::UNumberValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class ReadlineFeeder : public CmdFeeder, private ResClient
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool tty:1;
|
|
Packit |
8f70b4 |
bool ctty:1;
|
|
Packit |
8f70b4 |
bool add_newline:1;
|
|
Packit |
8f70b4 |
int eof_count;
|
|
Packit |
8f70b4 |
xstring_c cmd_buf;
|
|
Packit |
8f70b4 |
xstring_c for_history;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static bool readline_inited;
|
|
Packit |
8f70b4 |
void readline_init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(readline_inited)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
readline_inited=true;
|
|
Packit |
8f70b4 |
lftp_readline_init();
|
|
Packit |
8f70b4 |
lftp_rl_read_history();
|
|
Packit |
8f70b4 |
if(for_history)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
lftp_add_history_nodups(for_history);
|
|
Packit |
8f70b4 |
for_history.set(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Reconfig(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
ReadlineFeeder(const ArgV *args)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
tty=isatty(0);
|
|
Packit |
8f70b4 |
ctty=(tcgetpgrp(0)!=(pid_t)-1);
|
|
Packit |
8f70b4 |
add_newline=false;
|
|
Packit |
8f70b4 |
eof_count=0;
|
|
Packit |
8f70b4 |
if(args && args->count()>1)
|
|
Packit |
8f70b4 |
args->CombineQuotedTo(for_history);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
virtual ~ReadlineFeeder()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(readline_inited)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(res_save_cwd_history.QueryBool(0))
|
|
Packit |
8f70b4 |
cwd_history.Save();
|
|
Packit |
8f70b4 |
if(res_save_rl_history.QueryBool(0))
|
|
Packit |
8f70b4 |
lftp_rl_write_history();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool IsInteractive() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return tty;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool RealEOF()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return !tty || eof_count>3;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *NextCmd(class CmdExec *exec,const char *prompt)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(add_newline)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
add_newline=false;
|
|
Packit |
8f70b4 |
return "\n";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
::completion_shell=exec;
|
|
Packit |
8f70b4 |
::remote_completion=exec->remote_completion;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(tty)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
readline_init();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(ctty) // controlling terminal
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!in_foreground_pgrp())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// looks like we are in background. Can't read from tty
|
|
Packit |
8f70b4 |
exec->Timeout(500);
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
SignalHook::ResetCount(SIGINT);
|
|
Packit |
8f70b4 |
cmd_buf.set_allocated(lftp_readline(prompt));
|
|
Packit |
8f70b4 |
xmalloc_register_block(cmd_buf.get_non_const());
|
|
Packit |
8f70b4 |
if(cmd_buf && *cmd_buf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(exec->csh_history)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *history_value0=0;
|
|
Packit |
8f70b4 |
int expanded = lftp_history_expand (cmd_buf, &history_value0);
|
|
Packit |
8f70b4 |
if (expanded)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(history_value0)
|
|
Packit |
8f70b4 |
xmalloc_register_block(history_value0);
|
|
Packit |
8f70b4 |
xstring_ca history_value(history_value0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if (expanded < 0)
|
|
Packit |
8f70b4 |
fprintf (stderr, "%s\n", history_value.get());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* If there was an error, return nothing. */
|
|
Packit |
8f70b4 |
if (expanded < 0 || expanded == 2) /* 2 == print only */
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
exec->Timeout(0); // and retry immediately
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
cmd_buf.move_here(history_value);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
lftp_add_history_nodups(cmd_buf);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(cmd_buf==0 && exec->interactive)
|
|
Packit |
8f70b4 |
puts("exit");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(cmd_buf==0)
|
|
Packit |
8f70b4 |
eof_count++;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
eof_count=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else // not a tty
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(exec->interactive)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(*prompt)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char ch=*prompt++;
|
|
Packit |
8f70b4 |
if(ch!=1 && ch!=2)
|
|
Packit |
8f70b4 |
putchar(ch);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
cmd_buf.set_allocated(readline_from_file(0));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
::completion_shell=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(cmd_buf && last_char(cmd_buf)!='\n')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
exec->Timeout(0);
|
|
Packit |
8f70b4 |
add_newline=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return cmd_buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void clear()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!tty)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
lftp_rl_clear();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Reconfig(const char *) {
|
|
Packit |
8f70b4 |
lftp_rl_history_stifle(res_stifle_rl_history.Query(0));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
bool ReadlineFeeder::readline_inited;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define args (parent->args)
|
|
Packit |
8f70b4 |
#define exit_code (parent->exit_code)
|
|
Packit |
8f70b4 |
#define output (parent->output)
|
|
Packit |
8f70b4 |
#define session (parent->session)
|
|
Packit |
8f70b4 |
#define eprintf parent->eprintf
|
|
Packit |
8f70b4 |
CMD(history)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
enum { READ, WRITE, CLEAR, LIST } mode = LIST;
|
|
Packit |
8f70b4 |
const char *fn = NULL;
|
|
Packit |
8f70b4 |
static struct option history_options[]=
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
{"read",required_argument,0,'r'},
|
|
Packit |
8f70b4 |
{"write",required_argument,0,'w'},
|
|
Packit |
8f70b4 |
{"clear",no_argument,0,'c'},
|
|
Packit |
8f70b4 |
{"list",required_argument,0,'l'},
|
|
Packit |
8f70b4 |
{0,0,0,0}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
exit_code=0;
|
|
Packit |
8f70b4 |
int opt;
|
|
Packit |
8f70b4 |
while((opt=args->getopt_long("+r:w:cl",history_options,0))!=EOF) {
|
|
Packit |
8f70b4 |
switch(opt) {
|
|
Packit |
8f70b4 |
case 'r':
|
|
Packit |
8f70b4 |
mode = READ;
|
|
Packit |
8f70b4 |
fn = optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case 'w':
|
|
Packit |
8f70b4 |
mode = WRITE;
|
|
Packit |
8f70b4 |
fn = optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case 'c':
|
|
Packit |
8f70b4 |
mode = CLEAR;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case 'l':
|
|
Packit |
8f70b4 |
mode = LIST;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case '?':
|
|
Packit |
8f70b4 |
eprintf(_("Try `help %s' for more information.\n"),args->a0());
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int cnt = 16;
|
|
Packit |
8f70b4 |
if(const char *arg = args->getcurr()) {
|
|
Packit |
8f70b4 |
if(!strcasecmp(arg, "all"))
|
|
Packit |
8f70b4 |
cnt = -1;
|
|
Packit |
8f70b4 |
else if(isdigit((unsigned char)arg[0]))
|
|
Packit |
8f70b4 |
cnt = atoi(arg);
|
|
Packit |
8f70b4 |
else {
|
|
Packit |
8f70b4 |
eprintf(_("%s: %s - not a number\n"), args->a0(), args->getcurr());
|
|
Packit |
8f70b4 |
exit_code=1;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(mode) {
|
|
Packit |
8f70b4 |
case READ:
|
|
Packit |
8f70b4 |
if(int err = lftp_history_read(fn)) {
|
|
Packit |
8f70b4 |
eprintf("%s: %s: %s\n", args->a0(), fn, strerror(err));
|
|
Packit |
8f70b4 |
exit_code=1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case WRITE:
|
|
Packit |
8f70b4 |
if(int err = lftp_history_write(fn)) {
|
|
Packit |
8f70b4 |
eprintf("%s: %s: %s\n", args->a0(), fn, strerror(err));
|
|
Packit |
8f70b4 |
exit_code=1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case LIST:
|
|
Packit |
8f70b4 |
lftp_history_list(cnt);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case CLEAR:
|
|
Packit |
8f70b4 |
lftp_history_clear();
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
CMD(attach)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *pid_s=args->getarg(1);
|
|
Packit |
8f70b4 |
if(!pid_s) {
|
|
Packit |
8f70b4 |
xstring& path=AcceptTermFD::get_sock_path(1);
|
|
Packit |
8f70b4 |
path.rtrim('1');
|
|
Packit |
8f70b4 |
path.append('*');
|
|
Packit |
8f70b4 |
glob_t g;
|
|
Packit |
8f70b4 |
glob(path, 0, NULL, &g);
|
|
Packit |
8f70b4 |
for(size_t i=0; i
|
|
Packit |
8f70b4 |
const char *sock_path=g.gl_pathv[i];
|
|
Packit |
8f70b4 |
pid_s=strrchr(sock_path,'-');
|
|
Packit |
8f70b4 |
if(!pid_s)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
pid_s++;
|
|
Packit |
8f70b4 |
int p=atoi(pid_s);
|
|
Packit |
8f70b4 |
if(p<=1) {
|
|
Packit |
8f70b4 |
pid_s=0;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(kill(p,0)==-1) {
|
|
Packit |
8f70b4 |
if(errno==ESRCH) {
|
|
Packit |
8f70b4 |
eprintf("%s: removing stale socket `%s'.\n",args->a0(),sock_path);
|
|
Packit |
8f70b4 |
if(unlink(sock_path)==-1)
|
|
Packit |
8f70b4 |
eprintf("%s: unlink(%s): %s\n",args->a0(),sock_path,strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pid_s=0;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pid_s=alloca_strdup(pid_s);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
globfree(&g);
|
|
Packit |
8f70b4 |
if(!pid_s) {
|
|
Packit |
8f70b4 |
eprintf("%s: no backgrounded lftp processes found.\n",args->a0());
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int pid=atoi(pid_s);
|
|
Packit |
8f70b4 |
SMTaskRef<SendTermFD> term_sender(new SendTermFD(pid));
|
|
Packit |
8f70b4 |
while(!term_sender->Done()) {
|
|
Packit |
8f70b4 |
SMTask::Schedule();
|
|
Packit |
8f70b4 |
SMTask::Block();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
exit_code=0;
|
|
Packit |
8f70b4 |
if(term_sender->Failed()) {
|
|
Packit |
8f70b4 |
eprintf("%s\n",term_sender->ErrorText());
|
|
Packit |
8f70b4 |
exit_code=1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#undef args
|
|
Packit |
8f70b4 |
#undef exit_code
|
|
Packit |
8f70b4 |
#undef output
|
|
Packit |
8f70b4 |
#undef session
|
|
Packit |
8f70b4 |
#undef eprintf
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void sig_term(int sig)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
printf(_("[%u] Terminated by signal %d. %s\n"),(unsigned)getpid(),sig,SMTask::now.IsoDateTime());
|
|
Packit |
8f70b4 |
if(top_exec) {
|
|
Packit |
8f70b4 |
top_exec->KillAll();
|
|
Packit |
8f70b4 |
alarm(30);
|
|
Packit |
8f70b4 |
while(Job::NumberOfJobs()>0) {
|
|
Packit |
8f70b4 |
SMTask::Schedule();
|
|
Packit |
8f70b4 |
SMTask::Block();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
exit(1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void detach()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGINT);
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGHUP);
|
|
Packit |
8f70b4 |
SignalHook::Ignore(SIGTSTP);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *home=get_lftp_data_dir();
|
|
Packit |
8f70b4 |
if(home)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring& log=xstring::get_tmp(home);
|
|
Packit |
8f70b4 |
if(access(log,F_OK)==-1)
|
|
Packit |
8f70b4 |
log.append("_log");
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
log.append("/log");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int fd=open(log,O_WRONLY|O_APPEND|O_CREAT,0600);
|
|
Packit |
8f70b4 |
if(fd>=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dup2(fd,1); // stdout
|
|
Packit |
8f70b4 |
dup2(fd,2); // stderr
|
|
Packit |
8f70b4 |
if(fd!=1 && fd!=2)
|
|
Packit |
8f70b4 |
close(fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *c="debug";
|
|
Packit |
8f70b4 |
ResMgr::Set("log:show-pid",c,"yes");
|
|
Packit |
8f70b4 |
ResMgr::Set("log:show-time",c,"yes");
|
|
Packit |
8f70b4 |
ResMgr::Set("log:show-ctx",c,"yes");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
close(0); // close stdin.
|
|
Packit |
8f70b4 |
open("/dev/null",O_RDONLY); // reopen it, just in case.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef HAVE_SETSID
|
|
Packit |
8f70b4 |
setsid(); // start a new session.
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
SignalHook::Handle(SIGTERM,sig_term);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void move_to_background()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// notify jobs
|
|
Packit |
8f70b4 |
Job::lftpMovesToBackground_ToAll();
|
|
Packit |
8f70b4 |
// wait they do something, but no more than 1 sec.
|
|
Packit |
8f70b4 |
SMTask::RollAll(TimeInterval(1,0));
|
|
Packit |
8f70b4 |
// if all jobs terminated, don't really move to bg.
|
|
Packit |
8f70b4 |
if(Job::NumberOfJobs()==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
top_exec->AtBackground();
|
|
Packit |
8f70b4 |
top_exec->WaitDone();
|
|
Packit |
8f70b4 |
if(Job::NumberOfJobs()==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pid_t pid=fork();
|
|
Packit |
8f70b4 |
switch(pid)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(0): // child
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pid=getpid();
|
|
Packit |
8f70b4 |
detach();
|
|
Packit |
8f70b4 |
printf(_("[%u] Started. %s\n"),(unsigned)pid,SMTask::now.IsoDateTime());
|
|
Packit |
8f70b4 |
SMTaskRef<AcceptTermFD> term_acceptor(new AcceptTermFD());
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SMTask::Schedule();
|
|
Packit |
8f70b4 |
if(Job::NumberOfJobs()==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
SMTask::Block();
|
|
Packit |
8f70b4 |
if(term_acceptor->Accepted()) {
|
|
Packit |
8f70b4 |
hook_signals();
|
|
Packit |
8f70b4 |
top_exec->SetInteractive();
|
|
Packit |
8f70b4 |
top_exec->SetStatusLine(new StatusLine(1));
|
|
Packit |
8f70b4 |
top_exec->SetCmdFeeder(new ReadlineFeeder(0));
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SMTask::Schedule();
|
|
Packit |
8f70b4 |
if(top_exec->Done() || term_acceptor->Detached()) {
|
|
Packit |
8f70b4 |
if(Job::NumberOfJobs()>0) {
|
|
Packit |
8f70b4 |
printf(_("[%u] Detaching from the terminal to complete transfers...\n"),(unsigned)pid);
|
|
Packit |
8f70b4 |
} else if(top_exec->Done()) {
|
|
Packit |
8f70b4 |
printf(_("[%u] Exiting and detaching from the terminal.\n"),(unsigned)pid);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
term_acceptor->Detach();
|
|
Packit |
8f70b4 |
detach();
|
|
Packit |
8f70b4 |
printf(_("[%u] Detached from terminal. %s\n"),(unsigned)pid,SMTask::now.IsoDateTime());
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SMTask::Block();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
top_exec->AtExitBg();
|
|
Packit |
8f70b4 |
top_exec->AtTerminate();
|
|
Packit |
8f70b4 |
top_exec->WaitDone();
|
|
Packit |
8f70b4 |
printf(_("[%u] Finished. %s\n"),(unsigned)pid,SMTask::now.IsoDateTime());
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
default: // parent
|
|
Packit |
8f70b4 |
printf(_("[%u] Moving to background to complete transfers...\n"),
|
|
Packit |
8f70b4 |
(unsigned)pid);
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
_exit(0);
|
|
Packit |
8f70b4 |
case(-1):
|
|
Packit |
8f70b4 |
perror("fork()");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int lftp_slot(int count,int key)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!top_exec)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
char slot[2];
|
|
Packit |
8f70b4 |
slot[0]=key;
|
|
Packit |
8f70b4 |
slot[1]=0;
|
|
Packit |
8f70b4 |
top_exec->ChangeSlot(slot);
|
|
Packit |
8f70b4 |
lftp_rl_set_prompt(top_exec->MakePrompt());
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void source_if_exist(const char *rc)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(access(rc,R_OK)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
top_exec->FeedCmd("source ");
|
|
Packit |
8f70b4 |
top_exec->FeedCmd(rc);
|
|
Packit |
8f70b4 |
top_exec->FeedCmd("\n");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void tty_clear()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(top_exec)
|
|
Packit |
8f70b4 |
top_exec->pre_stdout();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// look for the option, remove it and return true if found
|
|
Packit |
8f70b4 |
static bool pick_option(int& argc,char **argv,const char *option)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=1; i
|
|
Packit |
8f70b4 |
if(!strcmp(argv[i],option)) {
|
|
Packit |
8f70b4 |
// remove the option, move trailing NULL too.
|
|
Packit |
8f70b4 |
memmove(argv+i,argv+i+1,(argc-i)*sizeof(*argv));
|
|
Packit |
8f70b4 |
argc--;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!strcmp(argv[i],"--")) // end of options
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *program_name;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int main(int argc,char **argv)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
program_name=argv[0];
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef SOCKS4
|
|
Packit |
8f70b4 |
SOCKSinit(program_name);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
setlocale (LC_ALL, "");
|
|
Packit |
8f70b4 |
setlocale (LC_NUMERIC, "C");
|
|
Packit |
8f70b4 |
bindtextdomain (PACKAGE, LOCALEDIR);
|
|
Packit |
8f70b4 |
textdomain (PACKAGE);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CmdExec::RegisterCommand("history",cmd_history,
|
|
Packit |
8f70b4 |
N_("history -w file|-r file|-c|-l [cnt]"),
|
|
Packit |
8f70b4 |
N_(" -w <file> Write history to file.\n"
|
|
Packit |
8f70b4 |
" -r <file> Read history from file; appends to current history.\n"
|
|
Packit |
8f70b4 |
" -c Clear the history.\n"
|
|
Packit |
8f70b4 |
" -l List the history (default).\n"
|
|
Packit |
8f70b4 |
"Optional argument cnt specifies the number of history lines to list,\n"
|
|
Packit |
8f70b4 |
"or \"all\" to list all entries.\n"));
|
|
Packit |
8f70b4 |
CmdExec::RegisterCommand("attach",cmd_attach,"attach [PID]",
|
|
Packit |
8f70b4 |
N_("Attach the terminal to specified backgrounded lftp process.\n"));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
top_exec=new CmdExec(0,0);
|
|
Packit |
8f70b4 |
hook_signals();
|
|
Packit |
8f70b4 |
top_exec->SetStatusLine(new StatusLine(1));
|
|
Packit |
8f70b4 |
Log::global=new Log("debug");
|
|
Packit |
8f70b4 |
Log::global->SetCB(tty_clear);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
source_if_exist(SYSCONFDIR"/lftp.conf");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!pick_option(argc,argv,"--norc")) {
|
|
Packit |
8f70b4 |
const char *home=getenv("HOME");
|
|
Packit |
8f70b4 |
if(home)
|
|
Packit |
8f70b4 |
source_if_exist(dir_file(home,".lftprc"));
|
|
Packit |
8f70b4 |
home=get_lftp_config_dir();
|
|
Packit |
8f70b4 |
if(home)
|
|
Packit |
8f70b4 |
source_if_exist(dir_file(home,"rc"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
top_exec->WaitDone();
|
|
Packit |
8f70b4 |
top_exec->SetTopLevel();
|
|
Packit |
8f70b4 |
top_exec->Fg();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Ref<ArgV> args(new ArgV(argc,argv));
|
|
Packit |
8f70b4 |
args->setarg(0,"lftp");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
lftp_feeder=new ReadlineFeeder(args);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
top_exec->ExecParsed(args.borrow());
|
|
Packit |
8f70b4 |
top_exec->WaitDone();
|
|
Packit |
8f70b4 |
int exit_code=top_exec->ExitCode();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
top_exec->AtExit();
|
|
Packit |
8f70b4 |
top_exec->WaitDone();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Job::NumberOfJobs()>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
top_exec->SetInteractive(false);
|
|
Packit |
8f70b4 |
move_to_background();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
top_exec->AtExitFg();
|
|
Packit |
8f70b4 |
top_exec->AtTerminate();
|
|
Packit |
8f70b4 |
top_exec->WaitDone();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
top_exec->KillAll();
|
|
Packit |
8f70b4 |
top_exec=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Job::Cleanup();
|
|
Packit |
8f70b4 |
ConnectionSlot::Cleanup();
|
|
Packit |
8f70b4 |
SessionPool::ClearAll();
|
|
Packit |
8f70b4 |
FileAccess::ClassCleanup();
|
|
Packit |
8f70b4 |
ProcWait::DeleteAll();
|
|
Packit |
8f70b4 |
IdNameCacheCleanup();
|
|
Packit |
8f70b4 |
SignalHook::Cleanup();
|
|
Packit |
8f70b4 |
Log::Cleanup();
|
|
Packit |
8f70b4 |
SMTask::Cleanup();
|
|
Packit |
8f70b4 |
return exit_code;
|
|
Packit |
8f70b4 |
}
|