**Problem:
With cmd:parallel=1 it works fine because CmdExec::Do() waits (returns
early) until the running job is finished before spawning the next one
in exec_parsed_command(). When it finishes, the exit code of that job
is stored in exit_code, that exec_parsed_command() will check (when
cmd:fail-exit=true) in order to see if it must end the program
(removing the feeder and emptying the buffer).

However when you have several in parallel, if CMD(something) doesn't
set exit_code=0, the next time exec_parsed_command() is called (that
is, the next command in the buffer) will think there was an error and
will prevent the rest of the commands from executing.

exit_code is set to 1 in exec_parsed_command() before making the new
job (new_job=c->creator(this);)  creator(this) calls a CMD(something)
in commands.cc and that will sometimes set exit_code=0 when it
finishes successfully, or ignore it (exit_code being 1)


**Tests:

.lftp/rc:
set cmd:fail-exit true;
set cmd:parallel 2;

lftp -f file:

-First example

file:
open fish://user:pass@ip;
chmod 755 a;
chmod 755 a;

chmod will only be executed once

-Second example

file:
get -c http://file1;
get -c http://file2;

Only file1 will be downloaded.

**Fix:

exit_code must be 0, or the fail-exit check must be changed to only
run if a job just finished, which isn't easy because some commands
don't make new jobs, the finish and just leave exit_code=1.

After making a new job, if a new object has actually been created,
AddNewJob is called. If the command is in the background, it is
executed and if not finished, suspended (put in the background) with
SuspendJob. The interesting part is that function also sets
exit_code=0.

When a job finishes, its status code is stored in exit_code. I've
tried to find if that wasn't always the case, but it seems all
external and built-in commands do it. So exit_code=1 shouldn't be
necessary while the jobs are running. I thought maybe it was made that
way because a job could somehow finish in an error state and bypassing
the place where its status code is put into exit_code, but I didn't
find any of such cases.

Also, because you can background a job whenever you want, that means
the exit_code of its CmdExec can be changed to 0 at any moment,
telling me it's value is not important.

If a job is not created in exec_parsed_command(), then the exit_code
is relevant, because that means the command has already been executed
and exit_code is storing a real value. However, if there is a new job,
it is supposed to exit and give a code. So, would the proper fix be
adding exit_code=0 to AddNewJob? it works, and that's what I
implemented.

Attachment: fail-exit.patch
Description: Binary data

Reply via email to