**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.
fail-exit.patch
Description: Binary data