Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to handle a password request when using QProcess for an rsync call?
Forum Update on Monday, May 27th 2025

How to handle a password request when using QProcess for an rsync call?

Scheduled Pinned Locked Moved Unsolved General and Desktop
9 Posts 5 Posters 649 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    BwvB
    wrote on 16 Dec 2023, 17:12 last edited by BwvB
    #1

    I want to use QProcess for an rsync call from my application to my NAS device.
    In short: when no password is needed, the code works perfectly (minimal example below). But for some rsync modules I need to provide a password. I cannot find a way how to trap this situation, pop-up a password dialog etc.

    Below follows a minimal, but complete program showing what I am trying to do: After compilation/linkage, the program is to be run with one argument, the same as would be provided to an rsync command from the command line. For instance, when I want to list the modules on my NAS device, called "diskstation", I can do that with rsync diskstation::
    The same information should be returned by running the below program, say ./a.out diskstation::
    where a.out is the default executable name on a linux platform.

    • a convenience macro TRC_MSGLN is defined to produce line-numbered feedback
    • A QProcess instance is defined. All its signals are connected to a lambda-slot, printing info, only to see what is going on.
    • the qprocess is started with rsync. We wait at most 10s for the process to finish.
    • After the process has terminated, the result is printed to std::cout.
    #include <QtCore/QByteArray>
    #include <QtCore/QProcess>
    
    #include <iostream>
    #include <string>
    
    #define TRC_MSGLN( s )                                 \
       {                                                   \
          std::cout << __LINE__ << ": " << s << std::endl; \
       }
    
    /*############################################################################*/
    /*############################################################################*/
    int main( int argc, char* argv[] )
    {
       QProcess qproc;
       QObject::connect( &qproc, &QProcess::readyReadStandardOutput, []() { TRC_MSGLN( "out: new data" ); } );
       QObject::connect( &qproc, &QProcess::readyReadStandardError, []() { TRC_MSGLN( "err: new data" ); } );
       QObject::connect( &qproc, &QProcess::started, []() { TRC_MSGLN( "started" ); } );
       QObject::connect( &qproc, &QProcess::finished, []( int ec ) { TRC_MSGLN( "finished: ec=" << ec ); } );
       QObject::connect( &qproc, &QProcess::stateChanged, []( auto s ) { TRC_MSGLN( "state changed:" << s ); } );
       QObject::connect( &qproc, &QProcess::errorOccurred, []( auto e ) { TRC_MSGLN( "error occurred:" << e ); } );
    
       qproc.start( "rsync", QStringList() << argv[1] );
    
       if ( !qproc.waitForFinished( 10000 ) )
       {
          TRC_MSGLN( "wait for finished failed ..." );
          return -2;
       }
    
       auto result = qproc.readAllStandardOutput().split( '\n' ); // type: QList<QByteArray>
    
       for ( int count = 0; const auto& r: result )
       {
          TRC_MSGLN( ++count << ":" << r.toStdString() );
       }
    
       return 0;
    }
    

    As said, this works perfectly when no password needs to be given. But when a password is needed, this is prompted for in the terminal.
    None of the connected channels show any sign of data being available (that is, the password prompt goes undetected by QProcess). For instance (waiting for the time-out of 10s to occur) the terminal shows

    21: state changed:1
    21: state changed:2
    19: started
    Password: 28: wait for finished failed ...
    QProcess: Destroyed while process ("rsync") is still running.
    21: state changed:0
    22: error occurred:1
    20: finished: ec=9
    

    Apparently, I am missing something here. Can anybody be of help?

    Finally, the program above (main.cpp) can be compiled/linked by (linux)
    g++ main.cpp -std=c++20 -fPIC -I$QTDIR/include -L$QTDIR/lib -lQt6Core
    producing the executable a.out
    $QTDIR refers to the qt installation directory.

    You help is appreciated!

    Bertwim

    P J 2 Replies Last reply 16 Dec 2023, 18:48
    0
    • B BwvB
      16 Dec 2023, 17:12

      I want to use QProcess for an rsync call from my application to my NAS device.
      In short: when no password is needed, the code works perfectly (minimal example below). But for some rsync modules I need to provide a password. I cannot find a way how to trap this situation, pop-up a password dialog etc.

      Below follows a minimal, but complete program showing what I am trying to do: After compilation/linkage, the program is to be run with one argument, the same as would be provided to an rsync command from the command line. For instance, when I want to list the modules on my NAS device, called "diskstation", I can do that with rsync diskstation::
      The same information should be returned by running the below program, say ./a.out diskstation::
      where a.out is the default executable name on a linux platform.

      • a convenience macro TRC_MSGLN is defined to produce line-numbered feedback
      • A QProcess instance is defined. All its signals are connected to a lambda-slot, printing info, only to see what is going on.
      • the qprocess is started with rsync. We wait at most 10s for the process to finish.
      • After the process has terminated, the result is printed to std::cout.
      #include <QtCore/QByteArray>
      #include <QtCore/QProcess>
      
      #include <iostream>
      #include <string>
      
      #define TRC_MSGLN( s )                                 \
         {                                                   \
            std::cout << __LINE__ << ": " << s << std::endl; \
         }
      
      /*############################################################################*/
      /*############################################################################*/
      int main( int argc, char* argv[] )
      {
         QProcess qproc;
         QObject::connect( &qproc, &QProcess::readyReadStandardOutput, []() { TRC_MSGLN( "out: new data" ); } );
         QObject::connect( &qproc, &QProcess::readyReadStandardError, []() { TRC_MSGLN( "err: new data" ); } );
         QObject::connect( &qproc, &QProcess::started, []() { TRC_MSGLN( "started" ); } );
         QObject::connect( &qproc, &QProcess::finished, []( int ec ) { TRC_MSGLN( "finished: ec=" << ec ); } );
         QObject::connect( &qproc, &QProcess::stateChanged, []( auto s ) { TRC_MSGLN( "state changed:" << s ); } );
         QObject::connect( &qproc, &QProcess::errorOccurred, []( auto e ) { TRC_MSGLN( "error occurred:" << e ); } );
      
         qproc.start( "rsync", QStringList() << argv[1] );
      
         if ( !qproc.waitForFinished( 10000 ) )
         {
            TRC_MSGLN( "wait for finished failed ..." );
            return -2;
         }
      
         auto result = qproc.readAllStandardOutput().split( '\n' ); // type: QList<QByteArray>
      
         for ( int count = 0; const auto& r: result )
         {
            TRC_MSGLN( ++count << ":" << r.toStdString() );
         }
      
         return 0;
      }
      

      As said, this works perfectly when no password needs to be given. But when a password is needed, this is prompted for in the terminal.
      None of the connected channels show any sign of data being available (that is, the password prompt goes undetected by QProcess). For instance (waiting for the time-out of 10s to occur) the terminal shows

      21: state changed:1
      21: state changed:2
      19: started
      Password: 28: wait for finished failed ...
      QProcess: Destroyed while process ("rsync") is still running.
      21: state changed:0
      22: error occurred:1
      20: finished: ec=9
      

      Apparently, I am missing something here. Can anybody be of help?

      Finally, the program above (main.cpp) can be compiled/linked by (linux)
      g++ main.cpp -std=c++20 -fPIC -I$QTDIR/include -L$QTDIR/lib -lQt6Core
      producing the executable a.out
      $QTDIR refers to the qt installation directory.

      You help is appreciated!

      Bertwim

      P Offline
      P Offline
      Pl45m4
      wrote on 16 Dec 2023, 18:48 last edited by Pl45m4
      #2

      @BwvB said in How to handle a password request when using QProcess for an rsync call?:

      But when a password is needed, this is prompted for in the terminal.
      None of the connected channels show any sign of data being available (that is, the password prompt goes undetected by QProcess).

      Check the rsync documentation.
      Doesn't it provide cmd line options to set a password or a path to some auth token or pw file?!
      You have to set that before together with the other args.


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      B 1 Reply Last reply 16 Dec 2023, 19:55
      1
      • P Pl45m4
        16 Dec 2023, 18:48

        @BwvB said in How to handle a password request when using QProcess for an rsync call?:

        But when a password is needed, this is prompted for in the terminal.
        None of the connected channels show any sign of data being available (that is, the password prompt goes undetected by QProcess).

        Check the rsync documentation.
        Doesn't it provide cmd line options to set a password or a path to some auth token or pw file?!
        You have to set that before together with the other args.

        B Offline
        B Offline
        BwvB
        wrote on 16 Dec 2023, 19:55 last edited by
        #3

        @Pl45m4 That is not my question. I want to capture the response from the process and act on that. But I don't understand how to do this with QProcess.

        Axel SpoerlA 1 Reply Last reply 17 Dec 2023, 07:27
        0
        • B BwvB
          16 Dec 2023, 19:55

          @Pl45m4 That is not my question. I want to capture the response from the process and act on that. But I don't understand how to do this with QProcess.

          Axel SpoerlA Offline
          Axel SpoerlA Offline
          Axel Spoerl
          Moderators
          wrote on 17 Dec 2023, 07:27 last edited by
          #4

          @BwvB
          The way rsync (and most of the cmd tools dealing with passwords, e.g. sudo or passwd) are implemented, prevents intercepting the password input. If you flip it around and assume that it would actually possible to react in QProcess, this would be the ideal way to find out someone's password.

          OTOH, if you rsync into a remote machine, you can pretty much rely on the fact that a password is needed. sshpass is a handy, non interactive tool for such usecases.

          I often use:
          /usr/bin/rsync -ratlz --rsh="/usr/bin/sshpass -p password ssh -o StrictHostKeyChecking=no -l username" localDirectory host:/remote/path

          Software Engineer
          The Qt Company, Oslo

          B 1 Reply Last reply 17 Dec 2023, 09:49
          2
          • B BwvB
            16 Dec 2023, 17:12

            I want to use QProcess for an rsync call from my application to my NAS device.
            In short: when no password is needed, the code works perfectly (minimal example below). But for some rsync modules I need to provide a password. I cannot find a way how to trap this situation, pop-up a password dialog etc.

            Below follows a minimal, but complete program showing what I am trying to do: After compilation/linkage, the program is to be run with one argument, the same as would be provided to an rsync command from the command line. For instance, when I want to list the modules on my NAS device, called "diskstation", I can do that with rsync diskstation::
            The same information should be returned by running the below program, say ./a.out diskstation::
            where a.out is the default executable name on a linux platform.

            • a convenience macro TRC_MSGLN is defined to produce line-numbered feedback
            • A QProcess instance is defined. All its signals are connected to a lambda-slot, printing info, only to see what is going on.
            • the qprocess is started with rsync. We wait at most 10s for the process to finish.
            • After the process has terminated, the result is printed to std::cout.
            #include <QtCore/QByteArray>
            #include <QtCore/QProcess>
            
            #include <iostream>
            #include <string>
            
            #define TRC_MSGLN( s )                                 \
               {                                                   \
                  std::cout << __LINE__ << ": " << s << std::endl; \
               }
            
            /*############################################################################*/
            /*############################################################################*/
            int main( int argc, char* argv[] )
            {
               QProcess qproc;
               QObject::connect( &qproc, &QProcess::readyReadStandardOutput, []() { TRC_MSGLN( "out: new data" ); } );
               QObject::connect( &qproc, &QProcess::readyReadStandardError, []() { TRC_MSGLN( "err: new data" ); } );
               QObject::connect( &qproc, &QProcess::started, []() { TRC_MSGLN( "started" ); } );
               QObject::connect( &qproc, &QProcess::finished, []( int ec ) { TRC_MSGLN( "finished: ec=" << ec ); } );
               QObject::connect( &qproc, &QProcess::stateChanged, []( auto s ) { TRC_MSGLN( "state changed:" << s ); } );
               QObject::connect( &qproc, &QProcess::errorOccurred, []( auto e ) { TRC_MSGLN( "error occurred:" << e ); } );
            
               qproc.start( "rsync", QStringList() << argv[1] );
            
               if ( !qproc.waitForFinished( 10000 ) )
               {
                  TRC_MSGLN( "wait for finished failed ..." );
                  return -2;
               }
            
               auto result = qproc.readAllStandardOutput().split( '\n' ); // type: QList<QByteArray>
            
               for ( int count = 0; const auto& r: result )
               {
                  TRC_MSGLN( ++count << ":" << r.toStdString() );
               }
            
               return 0;
            }
            

            As said, this works perfectly when no password needs to be given. But when a password is needed, this is prompted for in the terminal.
            None of the connected channels show any sign of data being available (that is, the password prompt goes undetected by QProcess). For instance (waiting for the time-out of 10s to occur) the terminal shows

            21: state changed:1
            21: state changed:2
            19: started
            Password: 28: wait for finished failed ...
            QProcess: Destroyed while process ("rsync") is still running.
            21: state changed:0
            22: error occurred:1
            20: finished: ec=9
            

            Apparently, I am missing something here. Can anybody be of help?

            Finally, the program above (main.cpp) can be compiled/linked by (linux)
            g++ main.cpp -std=c++20 -fPIC -I$QTDIR/include -L$QTDIR/lib -lQt6Core
            producing the executable a.out
            $QTDIR refers to the qt installation directory.

            You help is appreciated!

            Bertwim

            J Offline
            J Offline
            JonB
            wrote on 17 Dec 2023, 08:15 last edited by JonB
            #5

            @BwvB

            @Pl45m4 That is not my question. I want to capture the response from the process and act on that. But I don't understand how to do this with QProcess.

            I am always interested in anything QProcess, especially under Linux :)

            First a couple of preliminaries about your code. I am "surprised" it works given that you do not create any kind of QCoreApplication. It is also not a great idea (at least while you have a problem) using QProcess signal/slots at the same time as calling waitForFinished() in case the way that works interferes; you might try without that (you would need to run return app.exec()). But neither of these may affect the behaviour.

            I believe/suspect the "hang" you see is from where the rsync's input is attached to. See enum QProcess::InputChannelMode. The default is QProcess::ManagedInputChannel:

            QProcess manages the input of the running process. This is the default input channel mode of QProcess.

            You should change via void QProcess::setInputChannelMode(QProcess::InputChannelMode mode) to QProcess::ForwardedInputChannel:

            QProcess forwards the input of the main process onto the running process. The child process reads its standard input from the same source as the main process. Note that the main process must not try to read its standard input while the child process is running.

            This should mean that if your Qt calling program stdin is attached to a terminal then the rsync can read from that terminal too.

            You may even now see the "prompt" message arrive in your code via readRead...(). rsync code may well have code like:

            if isatty(0)
                fprintf(stderr, "Enter password:");
            read(0, password, sizeof(password));
            

            so the message part would require stdin to be attached to a terminal, not a pipe/redirection, as it is with ManagedInputChannel.

            It may do this by calling getpass(3):

            The getpass() function opens /dev/tty (the controlling terminal
            of the process), outputs the string prompt, turns off echoing,
            reads one line (the "password"), restores the terminal state and
            closes /dev/tty again.

            At the moment it is expecting its input from the calling Qt app code. Without the ForwardedInputChannel you may find that you can go proc.write("Password\n"), probably in response to the started signal, to send the password programmatically from the calling app.

            Finally, to test this all outside of Qt/QProcess you can try:

            • Use system("rsync ...") instead of QProcess from your code and see how it behaves.
            • Outside of any code of your own in terminal, try something like
            rsync ... < input_file > out_file 2> err_file
            

            This should put you in something like the default QProcess redirection situation to play with/understand how rsync behaves.

            B 1 Reply Last reply 17 Dec 2023, 09:54
            3
            • Axel SpoerlA Axel Spoerl
              17 Dec 2023, 07:27

              @BwvB
              The way rsync (and most of the cmd tools dealing with passwords, e.g. sudo or passwd) are implemented, prevents intercepting the password input. If you flip it around and assume that it would actually possible to react in QProcess, this would be the ideal way to find out someone's password.

              OTOH, if you rsync into a remote machine, you can pretty much rely on the fact that a password is needed. sshpass is a handy, non interactive tool for such usecases.

              I often use:
              /usr/bin/rsync -ratlz --rsh="/usr/bin/sshpass -p password ssh -o StrictHostKeyChecking=no -l username" localDirectory host:/remote/path

              B Offline
              B Offline
              BwvB
              wrote on 17 Dec 2023, 09:49 last edited by
              #6

              @Axel-Spoerl Ah thanks. This answer helps me understanding the situation.

              1 Reply Last reply
              0
              • J JonB
                17 Dec 2023, 08:15

                @BwvB

                @Pl45m4 That is not my question. I want to capture the response from the process and act on that. But I don't understand how to do this with QProcess.

                I am always interested in anything QProcess, especially under Linux :)

                First a couple of preliminaries about your code. I am "surprised" it works given that you do not create any kind of QCoreApplication. It is also not a great idea (at least while you have a problem) using QProcess signal/slots at the same time as calling waitForFinished() in case the way that works interferes; you might try without that (you would need to run return app.exec()). But neither of these may affect the behaviour.

                I believe/suspect the "hang" you see is from where the rsync's input is attached to. See enum QProcess::InputChannelMode. The default is QProcess::ManagedInputChannel:

                QProcess manages the input of the running process. This is the default input channel mode of QProcess.

                You should change via void QProcess::setInputChannelMode(QProcess::InputChannelMode mode) to QProcess::ForwardedInputChannel:

                QProcess forwards the input of the main process onto the running process. The child process reads its standard input from the same source as the main process. Note that the main process must not try to read its standard input while the child process is running.

                This should mean that if your Qt calling program stdin is attached to a terminal then the rsync can read from that terminal too.

                You may even now see the "prompt" message arrive in your code via readRead...(). rsync code may well have code like:

                if isatty(0)
                    fprintf(stderr, "Enter password:");
                read(0, password, sizeof(password));
                

                so the message part would require stdin to be attached to a terminal, not a pipe/redirection, as it is with ManagedInputChannel.

                It may do this by calling getpass(3):

                The getpass() function opens /dev/tty (the controlling terminal
                of the process), outputs the string prompt, turns off echoing,
                reads one line (the "password"), restores the terminal state and
                closes /dev/tty again.

                At the moment it is expecting its input from the calling Qt app code. Without the ForwardedInputChannel you may find that you can go proc.write("Password\n"), probably in response to the started signal, to send the password programmatically from the calling app.

                Finally, to test this all outside of Qt/QProcess you can try:

                • Use system("rsync ...") instead of QProcess from your code and see how it behaves.
                • Outside of any code of your own in terminal, try something like
                rsync ... < input_file > out_file 2> err_file
                

                This should put you in something like the default QProcess redirection situation to play with/understand how rsync behaves.

                B Offline
                B Offline
                BwvB
                wrote on 17 Dec 2023, 09:54 last edited by
                #7

                @JonB Thanks for the detailed answer. At lot of things to experiment with. Next week, I hope to find some time to follow-up.

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SimonSchroeder
                  wrote on 18 Dec 2023, 09:02 last edited by
                  #8

                  If you really want to figure out if rsync requires a password or not, you need to parse the standard output of rsync and search for the prompt that asks for a password and then react accordingly. Connecting to readyReadStandardOutput would be a step in the right direction. It also means you have to fully embrace asynchronous programming. Everything after qproc.start(...) has to go somewhere else. You cannot use qproc.waitForFinished() as it blocks the event queue (and you will not receive the readyReadStandardOutput signal before everything else has finished. And you certainly need to run an event loop!

                  J 1 Reply Last reply 18 Dec 2023, 09:32
                  0
                  • S SimonSchroeder
                    18 Dec 2023, 09:02

                    If you really want to figure out if rsync requires a password or not, you need to parse the standard output of rsync and search for the prompt that asks for a password and then react accordingly. Connecting to readyReadStandardOutput would be a step in the right direction. It also means you have to fully embrace asynchronous programming. Everything after qproc.start(...) has to go somewhere else. You cannot use qproc.waitForFinished() as it blocks the event queue (and you will not receive the readyReadStandardOutput signal before everything else has finished. And you certainly need to run an event loop!

                    J Offline
                    J Offline
                    JonB
                    wrote on 18 Dec 2023, 09:32 last edited by JonB
                    #9

                    @SimonSchroeder
                    Although possible, I doubt that rsync sends the password prompt to standard output. More likely standard error or directly to controlling terminal. And if you read my post you will see that it is possible/likely that it only prompts if stdin is a terminal.

                    I think you are incorrect about the event loop and the signals when QProcess::waitForFinished() is called. Although I said it might be best not to use this if attaching signals, if you test it I think you will nonetheless find that all the signals work. OP's output already shows all the other signals are being delivered, I think there is nothing to read from rsync. waitForFinished() does not block the event queue, it runs its own loop.

                    1 Reply Last reply
                    1

                    1/9

                    16 Dec 2023, 17:12

                    • Login

                    • Login or register to search.
                    1 out of 9
                    • First post
                      1/9
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved