Purchase Linux CDs / DVDs / Flash Drives at OSDisc.com

Welcome to Our Community

While Linux.org has been around for a while, we recently changed management and had to purge most of the content (including users). If you signed up before April 23rd, 2017 please sign up again. Thanks!

  1. Follow us on twitter - we shoot all of our new original content out as well as random messages. https://twitter.com/linuxdotorg
    Dismiss Notice

Auto USB copy program

Discussion in 'General Linux' started by TheDennis, Jan 28, 2019.

  1. TheDennis

    TheDennis New Member

    Joined:
    Jan 23, 2019
    Messages:
    9
    Likes Received:
    2
    I made a c code to automatically copy a folder in an usb drive whenever you plug the stick in. In the "softwares that run at start" thing ( don't know the name in english), I added a new program, linked to the main.c class I made. But it obviously doesn't work. Ideas? (that's my first time doing this kind of things btw ;D)
    Code, if it helps:
    Code:
    #include <stdio.h>
    #include <dirent.h>
    #include <unistd.h>
    #include <stdlib.h>
    #define PATH "/media/dennis_orlando/ORLANDO D/Foto"
    
    int main(){
        int done = 0;
        while (1== 1){
                DIR *dir;
                dir = opendir(PATH);
                if (dir != NULL){
                    if (done == 0){
                        int a = system("echo password | cp -na '/media/dennis_orlando/ORLANDO D/Foto' '/home/dennis_orlando/Scrivania/'");
                        if (a == -1) printf("something went wrong while copying files");
                        else {
                            done = 1;
                            printf("\nsuccesfully copied files\n");
                        }
                    }
                }
                else done = 0;
                sleep(1);
        }
        return 0;
    }
    

    PS: I'm using Eclipse


    (Log in to hide this advertisement)


    EDIT: changed title of this thread
     
    #1 TheDennis, Jan 28, 2019
    Last edited: Feb 1, 2019
  2. Condobloke

    Condobloke Well-Known Member

    Joined:
    Apr 30, 2017
    Messages:
    560
    Likes Received:
    619
    @JasKinasis ....where are you mate ?....this looks like it might be right up your alley.

    (definitely not my forte !!)
     
  3. JasKinasis

    JasKinasis Well-Known Member

    Joined:
    Apr 25, 2017
    Messages:
    331
    Likes Received:
    641
    The main thing you are missing is the -r (recursive) flag in your cp command.
    Without that the cp command will fail to copy the content of the directory.

    Another problem is the infinite loop you have set up.
    I would change the condition to while (done != 1). Otherwise, after copying the files - your program will reiterate again, re-detect the source directory and run the cp command over and over again. Which will probably be as bad as not doing anything!

    By changing the condition of the while loop, your program will only run until the required directory appears and is copied successfully. As soon as the files have been copied, it will end.

    Also, the sleep() command should only be used if we need to reiterate through the loop again. We don't need to sleep the process after successfully copying the files - it would make more sense to just end the program straight away.

    So I have put the sleep inside the else condition. And setting the value of done to zero in the else is redundant. It is initialised to zero when the program starts up and only gets changed to 1 when the files have been copied. Which is immediately before the program ends.

    Also, in the case where there is a problem copying the files - I have made the program exit with an error status. Otherwise you are likely to end up getting the error message over and over again as it tries and fails to copy the files....

    To test the code - I made a couple of test directories.
    /home/jason/tmp/dir1/ <<<< Note no space in the directory name
    /home/jason/tmp/dir2/

    I set up the program to look for a source directory called "/home/jason/tmp/dir 1/" <<< Note the space
    And then when "dir 1" is detected it recursively copies all of "dir 1" to "/home/jason/tmp/dir2/".
    After building your program and running it in a terminal, the program went into its loop because it could not find "dir 1". (my directory was called "dir1")

    I opened up a second terminal window and executed the following command:
    Code:
    mv /home/jason/tmp/dir1 /home/jason/tmp/dir\ 1/
    which renamed "dir1" to "dir 1".
    And immediately I got a message in my other terminal window saying "sucessfully copied files".
    And I quickly navigated into /home/jason/tmp/dir2/ to see that "dir 1" and its contents were copied to dir2!

    So with the changes I have suggested, your code should work and should look something like this:
    Code:
    #include <stdio.h>
    #include <dirent.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    #define PATH "/media/dennis_orlando/ORLANDO D/Foto"
    
    int main()
    {
        int done = 0;
        while (done != 1)
       {
                DIR *dir;
                dir = opendir(PATH);
                if (dir != NULL){
                    if (done == 0)
                   {
                       int a = system("echo password | cp -na '/media/dennis_orlando/ORLANDO D/Foto' '/home/dennis_orlando/Scrivania/'");
                       if (a == -1) 
                       {
                           printf("something went wrong while copying files");
                           return 1;
                       }
                       else
                       {
                            done = 1;
                            printf("\nsuccesfully copied files\n");
                        }
                    }
                }
                else
                   sleep(1);
        }
        return 0;
    }
    
    I just compiled and linked using gcc:
    gcc main.c -oname_of_program

    Simple!
     
    #3 JasKinasis, Jan 28, 2019
    Last edited: Jan 28, 2019
  4. JasKinasis

    JasKinasis Well-Known Member

    Joined:
    Apr 25, 2017
    Messages:
    331
    Likes Received:
    641
    As an aside - rather than using hard-coded paths in your program - you could make your program a bit more useful by accepting command-line parameters.
    For example,
    parameter 1 could be the path to the source directory to watch out for - the directory that you will be copying from
    parameter 2 could be the path to the output directory - where the source directory will be copied to

    That way, you could use several instances of your program to watch for different directories. It would not only make the program more useful for you and it could be useful for other people too.

    But doing all of this in C could be a bit of a PITA. You would need to add a lot of error checks in there.
    For example - your program currently does not check that the output directory exists. You might want to consider checking whether the output directory exists when the program starts. And you might want to consider checking that the output directory still exists when the source directory is found. Just in case the user, or the system removed or renamed the output directory.

    Personally, I would have performed a task like this using a shellscript instead of using C:
    copywhenexists.sh
    Code:
    #!/usr/bin/env bash
    
    # function to display usage information
    function usage
    {
       echo
       echo "$1"
       echo
       echo "Usage:"
       echo "copywhenexists.sh /path/to/source_dir /path/to/output_dir &"
       echo
       echo "will wait until /path/to/source_dir exists and copy its content to /path/to/output_dir"
       echo "Where: /path to source_dir is the source directory to watch for"
       echo "And: /path/to/output_dir is the directory to copy to when the source directory exists"
       echo "NOTE: The output directory must already exist"
       echo
       echo "This script will run in an infinite loop, waiting until the specified directory exists"
       echo "as soon as it exists - its contents will be recursively copied to the output directory!"
       echo
       echo "Alternative usage:"
       echo "copywhenexists.sh -h"
       echo
       echo "- Will display this usage information"
       echo
       echo
    }
    
    # if user asked for help - display usage information and exit
    if [[ $# -eq 1 ]] && [[ $1 -eq "-h" ]]; then
       usage "copywhenexists.sh Help"
       exit 0
    fi
    
    # if user failed to pass in two parameters
    # display usage information and exit with an error
    if [[ $# -ne 2 ]]; then
       usage "ERROR: Requires two parameters"
       exit 1
    fi
    
    # if target directory does not exist
    # display usage information and exit with an error
    if [[ ! -d "$2" ]];then
       usage "ERROR: $2 is not a valid directory!"
       exit 1
    fi
    
    # Wait until the source directory exists
    echo
    echo "Waiting for $1 to exist."
    echo "$1 will be copied to $2"
    echo
    while true; do
       if [[ -d "$1" ]]; then
           # double check the target directory still exists
           # in case the user or the system removed or renamed it
           # while we were waiting
           if [[ ! -d $2 ]]; then
               echo
               echo "ERROR: $2 no longer exists"
               echo
               exit 1
           fi
           # source directory exists: so copy files to target
           cp -rna "$1" "$2"
           if [[ ! $? ]]; then
               echo
               echo "Something went wrong while copying files"
               echo
               exit 1
           else
               echo
               echo "Successfully copied files"
               echo
               exit 0
           fi
       fi
       sleep 1
    done
    
    The above script only took a few minutes to knock up. It contains a few more lines of code than your C program, but it is a bit more robust - it has a lot of error checks and does not have hard-coded paths in it. There is even a help option. And it accepts command-line parameters, potentially allowing you to run several instances of the script - watching for different directories.

    With the above script, you could copy it into your personal bin directory /home/yourusername/bin/
    Then add another script in your bin directory - that you can run on startup, that runs copywhenexists.sh and tells it the directory to look out for and the directory to copy to.

    e.g.
    mywatchdirs.sh
    Code:
    #!/usr/bin/env bash
    
    copywhenexists.sh /media/dennis_orlando/ORLANDO\ D/Foto /home/dennis_orlando/Scrivania/ &
    
    If you had any other devices/directories that you wanted to automatically sync to somewhere on your PC - you can run additional instances of copywhenexists.sh in your mywatchdirs.sh.
    You set mywatchdirs.sh to run on startup and each time you start up - the script will run each instance of copywhenexists.sh in the background until the directories exist and their contents are copied.
     
  5. TheDennis

    TheDennis New Member

    Joined:
    Jan 23, 2019
    Messages:
    9
    Likes Received:
    2
    @JasKinasis

    Woah, didn't expect that much help xD
    The reason I use a while loop is to allow copying multiple times. If you got an error or you just pull out your usb to add more files, and then you want to stick it another time in, you should reboot the entire system to copy another time.

    I actually didn't think about sharing this, but I think it can be useful so let's give it a try :)

    As you said, I should use bash scripts because they are more linux-friendly. But I never used them:rolleyes: (I just UPGRADED from win10 like 3 days ago)
    ... but I see it's pretty much C, if not even better, so I don't think I will have many problems learning bash coding

    I like the command thing to allow the user to modify the directories: I think I'm gonna think about something to join toghether commands + the multiple instance thing you suggested. Maybe about storing a list of "copy-paste" directories (in an xml file or something), so you still have only 1 instance for as many directories as you want.
    Another problem I instantly saw was that people don't really copy 1kb files... it can take a bunch of time for the process to complete. I may be able to log a % to show the copy status (hope you understand), but I think an icon (maybe near the battery) would be cool to. But for all those ideas I need to get informations from that cp command: how big (in bytes) is the file and how many bytes did he already copy. I honestly don't have any idea, if not creating a cp command from scratch
     
    #5 TheDennis, Jan 29, 2019
    Last edited: Jan 29, 2019
  6. wizardfromoz

    wizardfromoz Super Moderator
    Staff Member Gold Supporter

    Joined:
    Apr 30, 2017
    Messages:
    2,294
    Likes Received:
    1,995
    G'day @TheDennis , how are you doing? :)

    I don't understand a lot of the above (yet!) ... I leave that to Jas (@JasKinasis ) ... He De Man! IMO :D... but I think the sort of thing you are talking about here

    ... is what we might call a progress indicator or progress bar.

    A Google search on

    linux progress indicator

    ... shows some interesting results, including

    https://linoxide.com/linux-how-to/show-progress-bar-linux-commands/

    https://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-shell-script

    and

    https://www.tecmint.com/advanced-copy-command-shows-progress-bar-while-copying-files/

    Do note that, while some of the articles are old (one goes back to 2008, another to 2013), they have current input to them dating as recently as 2017 and 2018, so may still be of use.

    Hope this helps, and I will watch this Thread with interest.

    Good luck

    Wizard
     
  7. TheDennis

    TheDennis New Member

    Joined:
    Jan 23, 2019
    Messages:
    9
    Likes Received:
    2
    We meet again wizard ;)
    That stackoverflow post has just made my day. I also figured out how to get informations from the copy command: I get the size of the file I want to copy and I compare it to the size of the file that's still being created. I'm currently busy with school, so I can't work on the code, but one day I'll finish it (I hope)
     
    wizardfromoz likes this.
  8. JasKinasis

    JasKinasis Well-Known Member

    Joined:
    Apr 25, 2017
    Messages:
    331
    Likes Received:
    641
    @TheDennis - Sorry for the delay in replying here - I've been ill for a few days.

    After seeing what your initial C code was doing - I merely suggested that a shell-script would probably be the best way of doing things. I didn't realise you had such big aims with your program.

    Also, in my post I made a few assumptions.
    I thought the infinite loop, even after the device was found was an accidental flaw in your logic. I didn't realise that was deliberate. I thought that you only wanted to wait until the device was plugged in and then copy everything once. I didn't realise you wanted to monitor the directory after it had been detected and copied from.

    So what you're saying is - after the device has been plugged in and the directory detected - you want all files recursively copied to the target directory. And then afterwards the directory should be monitored until any files are added or changed and then sync any changes across to the destination?

    If that's the case - that would require a bit of extra logic. I don't have my thinker screwed completely on ATM thanks to a nasty cold I've come down with. But I'm sure there are ways around this.

    However - If you want a progress bar to appear in the dock-bar/notification area of your desktop - that is another kettle of fish altogether. That would almost certainly require some C or C++ (or possibly another programming language - depending on your preferred desktop environment and the language bindings available to implement a widget in the notification area).

    It would complicate things quite a lot, because you'd suddenly have a lot more things to think about.
    Not only the workings of the code that deals with monitoring directories and copying files, but also with the GUI library you'll be using and other usage-based considerations that will complicate the logic and the code.

    But it is certainly a viable option. Your entire program could be set up as a GUI widget that sits in the notification area of the desktop when it is running.

    But you will need to carefully think about the features that you need for your program and get it all planned out BEFORE you start coding it.

    The code required to do something like that would be a lot more complex than the simple terminal program you posted originally. You'd need to break the project into several components, spread across multiple source-files rather than just one main.c.

    But it could potentially be a useful project! The project itself could be a good one for you to learn from and it certainly sounds like it might be something that users would be interested in!
     
    Rob and wizardfromoz like this.
  9. wizardfromoz

    wizardfromoz Super Moderator
    Staff Member Gold Supporter

    Joined:
    Apr 30, 2017
    Messages:
    2,294
    Likes Received:
    1,995
    Get well soon, Jas ... hit the Vitamin C :)

    Wiz
     

Share This Page