Find the answer to your Linux question:
Results 1 to 3 of 3
I've set about making a new "cp" command that has a progress indicator, timer and "eta" timer. I have it all put together for the most part ( what I ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Linux Newbie SagaciousKJB's Avatar
    Join Date
    Aug 2007
    Location
    Yakima, WA
    Posts
    162

    Making "cp" display progress, time elapsed, eta, transfer rate


    I've set about making a new "cp" command that has a progress indicator, timer and "eta" timer.

    I have it all put together for the most part ( what I want for it anyway ), but I want to have the "recursive" feature and I'm not sure how I would go about programming it. I've read a bit about "dirent.h" in the past but never really enough to be able to think up a recursive algorithm like that.

    Does anyone know of any place I can study one? I don't even know where to find the source to "cp" or track down the recursive algorithm in it, and I have a feeling most of its operation will be well over my head.

    Not to mention, I'm kind of wondering if it wouldn't be easier to modify "cp" with the code of my timer and everything rather than try to make a whole command from scratch.

    Here's the source of what I've got so far, I'm calling it "data_timer" as it is since it only copies an input file to an output file and times it at this point. You can compile it and run it to see what I mean, or just look at the "copyFile" function.

    So, can anyone give me any advice? Maybe there's even an application already out there that could save me some time, I'm not doing this as a project or anything like that, I'm just sick of not having this basic information when copying a file.

    Code:
    #define _FILE_OFFSET_BITS 64
    #include <errno.h>
    #include <stdio.h>
    #include <malloc.h>
    #include <unistd.h>
    #include <string.h>
    #include <time.h>
    
    void copyFile(FILE *inputFile, FILE *outputFile, off_t fileSize);
    off_t getFileSize(FILE *argFile);
    
    struct optionStruct
    {
            char inputFileName[256];
            char outputFileName[256];
            int outFile;
            int inFile;
            int Interval;
    };
    
    struct optionStruct options;
    
    
    int main(int argc, char *argv[])
    {
            if(argc == 1)
            {
                    printf("Usage: data_timer -i inputFile -o outputFile [-s polling interval, defaults to 3 seconds]\n");
                    return 1;
            }
    
            FILE *inputFile, *outputFile;
    
            int opt, errflg = 0;
    
            off_t fileSize;
    
            options.Interval = 3;
    
            while ((opt = getopt(argc, argv, ":o:i:s:")) != -1)
            {
                    switch(opt)
                    {
                            case 'o':
                                    if(optarg[0] == '-')
                                    {
                                            printf("Option -o requires an operand\n");
                                            errflg++;
                                    }
                                    else
                                    {
                                            outputFile = fopen(optarg,"wb");
                                            if(outputFile == NULL)
                                            {
                                                    perror(optarg);
                                                    extern errno;
                                            }
                                            strcpy(options.outputFileName,optarg);
                                            options.outFile = 1;
                                    }
                            break;
                            case 'i':
                                    if(optarg[0] == '-')
                                    {
                                            printf("Option -i requires an operand\n");
                                            errflg++;
                                    }
                                    else
                                    {
                                            inputFile = fopen(optarg,"rb");
                                            if(inputFile == NULL)
                                            {
                                                    perror(optarg);
                                                    extern errno;
                                            }
                                            fileSize = getFileSize(inputFile);
                                            strcpy(options.inputFileName,optarg);
                                            options.inFile = 1;
                                    }
                            break;
                            case 's':
                                    if(optarg[0] == '-')
                                    {
                                            printf("Option -s requires an operand\n");
                                            errflg++;
                                    }
                                    else
                                    {
                                            options.Interval = atoi(optarg);
                                    }
                            break;
                            case ':':
                                    printf("Option -%c requires an operand\n", optopt);
                                    errflg++;
                            break;
                            case '?':
                                    printf("Unrecognized option: -%c\n", optopt);
                                    errflg++;
                    }
            }
    
            if(errflg > 0)
            {
                    fclose(inputFile);
                    fclose(outputFile);
                    return 1;
            }
    
            if(options.inFile != 1)
            {
                    printf("Input file not give\n");
                    return 1;
            }
            if(options.outFile != 1)
            {
                    printf("Output file not given\n");
                    return 1;
            }
    
            copyFile(inputFile,outputFile,getFileSize(inputFile));
    
    
            fclose(inputFile);
            fclose(outputFile);
            return 0;
    }
    
    
    void copyFile(FILE *inputFile, FILE *outputFile, off_t fileSize)
    {
    
            int inputByte;
            off_t i;
            float txRate;
    
            int start, end;
    
            start = time(0);
    
            for(i = 0 ; i < fileSize; i++)
            {
                    inputByte = fgetc(inputFile);
                    fputc(inputByte,outputFile);
    
                    if( i % 1048576 == 0 && (time(0) - start) % options.Interval == 0)
                    {
                            system("clear");
                            txRate = (float)(i/1048576)  / (float)((time(0) - start));
                            printf("%.2lf MB/s\t", txRate);
                            printf("%%%.0lf\t %i ", ((float)i / (float)fileSize) * 100, i / 1048576);
                            printf(" / %i MB\n", fileSize/1048576);
                            printf(" eta ");
                            print_time( ((fileSize-i)/1048576) / (int)txRate );
                            printf(" elapsed ");
                            print_time(time(0) - start);
                            printf("\n");
                            printf("%s -> %s\n", options.inputFileName, options.outputFileName);
    
                    }
    
            }
    }
    
    off_t getFileSize(FILE *argFile)
    {
    
            off_t fileSize;
            fseeko(argFile,0L,SEEK_END);
            fileSize = ftello(argFile);
            fseeko(argFile,0L,SEEK_SET);
    
            return fileSize;
    }
    
    #define MINUTES 60
    #define HOURS 3600
    #define DAYS 86400
    #define WEEKS 604800
    #define MONTHS 2629743
    #define YEARS 31556926
    
    
    int print_time(int start_seconds)
    {
    
            int seconds = 0, minutes = 0, hours = 0, days = 0, weeks = 0, months = 0, years = 0;
    
            seconds = start_seconds % 60;
            minutes = (start_seconds / MINUTES) % 60;
            hours = (start_seconds / HOURS) % 24;
            days = (start_seconds / DAYS) % 7;
            weeks = (start_seconds / WEEKS) % 4;
            months = (start_seconds / MONTHS) % 12;
            years = (start_seconds / YEARS);
    
    
            if ( start_seconds >= MINUTES && start_seconds < HOURS)
                    printf("%im:%is", minutes, seconds);
            else if ( start_seconds >= HOURS && start_seconds < DAYS)
                    printf("%ih:%im:%is", hours, minutes, seconds);
            else if ( start_seconds >= DAYS && start_seconds < WEEKS)
                    printf("%id:%ih:%im:%is", days, hours, minutes, seconds);
            else if ( start_seconds >= WEEKS && start_seconds < MONTHS)
                    printf("%iw:%id:%ih:%im:%is", weeks, days, hours, minutes, seconds);
            else if (start_seconds >= MONTHS && start_seconds < YEARS)
                    printf("%iM:%iw:%id:%ih:%im:%is", months, weeks, days, hours, minutes, seconds);
            else if(start_seconds >= YEARS)
                    printf("%iy:%iM:%iw:%id:%ih:%im:%is", years, months, weeks, days, hours, minutes, seconds);
            else
                    printf("%is", seconds);
    
    
            return 0;
    }

  2. #2
    Linux Engineer GNU-Fan's Avatar
    Join Date
    Mar 2008
    Posts
    935
    cp is part of the Coreutils - GNU core utilities
    Debian GNU/Linux -- You know you want it.

  3. #3
    drl
    drl is offline
    Linux Engineer drl's Avatar
    Join Date
    Apr 2006
    Location
    Saint Paul, MN, USA / CentOS, Debian, Slackware, {Free, Open, Net}BSD, Solaris
    Posts
    1,283
    Hi.

    One approach is to use the standard copy, but to assign the details of monitoring to a shell script. There was one such script posted at how to have a cp progress bar? - The UNIX and Linux Forums

    Once you see how this works, it would be an additional step to make a preliminary pass over the directory structure that you will be copying to gather information about the number of items, say with find, and then post messages about directories & files remaining, etc., along with the status of the current file copy operation.

    You certainly could do this all in a c program, but one of the reasons for the programmable shell is to make your task easier. You can also use the resulting script as a model, and, if you like the way it works, then re-write it in c. It's far easier to change a script with a new or better idea, than it is to change a c program.

    In general, I like the various forms of progress mechanisms, whether it's a spinner, a bar that lengthens, a marker that moves back and forth, or a number that changes as the operation proceeds. However, most of the time my tasks are relatively simple, and I don't need them.

    Good luck ... cheers, drl
    Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
    90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
    We look forward to helping you with the challenge of the other 10%.
    ( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •