A small I/O bound program to copy N bytes from an input file to an output file.

How to write a C Program : A small I/O bound program to copy N bytes from an input file to an output file. May read the input file multiple times if N is larger than the size of the input file in C Programming Language ?


  1. /*
  2.  * Description: A small i/o bound program to copy N bytes from an input
  3.  *              file to an output file. May read the input file multiple
  4.  *              times if N is larger than the size of the input file.
  5.  */
  6. /* Include Flags */
  7. #define _GNU_SOURCE
  8. /* System Includes */
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <unistd.h>
  12. #include <errno.h>
  13. #include <fcntl.h>
  14. #include <string.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <sched.h>
  18. /* Local Defines */
  19. #define MAXFILENAMELENGTH 80
  20. #define DEFAULT_INPUTFILENAME "rwinput"
  21. #define DEFAULT_OUTPUTFILENAMEBASE "rwoutput"
  22. #define DEFAULT_BLOCKSIZE 1024
  23. #define DEFAULT_TRANSFERSIZE 1024*100
  24. int main(int argc, char* argv[]){
  25.         int i;
  26.     int rv;
  27.     int inputFD;
  28.     int outputFD;
  29.     int numProcesses;
  30.     char inputFilename[MAXFILENAMELENGTH];
  31.     char outputFilename[MAXFILENAMELENGTH];
  32.     char outputFilenameBase[MAXFILENAMELENGTH];
  33.     struct sched_param param;
  34.     ssize_t transfersize = 0;
  35.     ssize_t blocksize = 0;
  36.     char* transferBuffer = NULL;
  37.     ssize_t buffersize;
  38.     int policy;
  39.     ssize_t bytesRead = 0;
  40.     ssize_t totalBytesRead = 0;
  41.     int totalReads = 0;
  42.     ssize_t bytesWritten = 0;
  43.     ssize_t totalBytesWritten = 0;
  44.     int totalWrites = 0;
  45.     int inputFileResets = 0;
  46.     pid_t id;
  47.    
  48.     /* Process program arguments to select run-time parameters */
  49.     /* Set supplied transfer size or default if not supplied */
  50.     if(argc < 2){
  51.         transfersize = DEFAULT_TRANSFERSIZE;
  52.     }
  53.     else{
  54.         transfersize = atol(argv[1]);
  55.         if(transfersize < 1){
  56.             fprintf(stderr, "Bad transfersize value\n");
  57.             exit(EXIT_FAILURE);
  58.         }
  59.     }
  60.     /* Set supplied block size or default if not supplied */
  61.     if(argc < 3){
  62.         blocksize = DEFAULT_BLOCKSIZE;
  63.     }
  64.     else{
  65.         blocksize = atol(argv[2]);
  66.         if(blocksize < 1){
  67.             fprintf(stderr, "Bad blocksize value\n");
  68.             exit(EXIT_FAILURE);
  69.         }
  70.     }
  71.     /* Set supplied input filename or default if not supplied */
  72.     if(argc < 4){
  73.         if(strnlen(DEFAULT_INPUTFILENAME, MAXFILENAMELENGTH) >= MAXFILENAMELENGTH){
  74.             fprintf(stderr, "Default input filename too long\n");
  75.             exit(EXIT_FAILURE);
  76.         }
  77.         strncpy(inputFilename, DEFAULT_INPUTFILENAME, MAXFILENAMELENGTH);
  78.     }
  79.     else{
  80.         if(strnlen(argv[3], MAXFILENAMELENGTH) >= MAXFILENAMELENGTH){
  81.             fprintf(stderr, "Input filename too long\n");
  82.             exit(EXIT_FAILURE);
  83.         }
  84.         strncpy(inputFilename, argv[3], MAXFILENAMELENGTH);
  85.     }
  86.     /* Set supplied output filename base or default if not supplied */
  87.     if(argc < 5){
  88.         if(strnlen(DEFAULT_OUTPUTFILENAMEBASE, MAXFILENAMELENGTH) >= MAXFILENAMELENGTH){
  89.             fprintf(stderr, "Default output filename base too long\n");
  90.             exit(EXIT_FAILURE);
  91.         }
  92.         strncpy(outputFilenameBase, DEFAULT_OUTPUTFILENAMEBASE, MAXFILENAMELENGTH);
  93.     }
  94.     else{
  95.         if(strnlen(argv[4], MAXFILENAMELENGTH) >= MAXFILENAMELENGTH){
  96.             fprintf(stderr, "Output filename base is too long\n");
  97.             exit(EXIT_FAILURE);
  98.         }
  99.         strncpy(outputFilenameBase, argv[4], MAXFILENAMELENGTH);
  100.     }
  101.    
  102.     /* Set policy if supplied */
  103.     if(argc > 5){
  104.       if(!strcmp(argv[5], "SCHED_OTHER")){
  105.                 policy = SCHED_OTHER;
  106.                 printf("OTHER!\n");
  107.       }
  108.       else if(!strcmp(argv[5], "SCHED_FIFO")){
  109.                 policy = SCHED_FIFO;
  110.                 printf("FIFO!\n");
  111.       }
  112.       else if(!strcmp(argv[5], "SCHED_RR")){
  113.                 policy = SCHED_RR;
  114.                 printf("RR!\n");
  115.       }
  116.       else{
  117.                 fprintf(stderr, "Unhandeled scheduling policy\n");
  118.                 exit(EXIT_FAILURE);
  119.       }
  120.     }
  121.     else{
  122.         policy = SCHED_OTHER;
  123.     }
  124.     printf("argv[5] is: \n", argv[5]);
  125.     printf("policy is: %d\n", policy);
  126.         /* Set process to max prioty for given scheduler */
  127.     param.sched_priority = sched_get_priority_max(policy);
  128.    
  129.     /* Set new scheduler policy */
  130.     fprintf(stdout, "Current Scheduling Policy: %d\n", sched_getscheduler(0));
  131.     fprintf(stdout, "Setting Scheduling Policy to: %d\n", policy);
  132.     if(sched_setscheduler(0, policy, &param)){
  133.         perror("Error setting scheduler policy");
  134.         exit(EXIT_FAILURE);
  135.     }
  136.     fprintf(stdout, "New Scheduling Policy: %d\n", sched_getscheduler(0));
  137.     /* Set number of processes if supplied */
  138.     if(argc > 6){
  139.       numProcesses = atoi(argv[6]);
  140.       if(numProcesses <= 0){
  141.         fprintf(stderr, "Too few processes\n");
  142.         exit(EXIT_FAILURE);
  143.       }
  144.     }
  145.     else{
  146.         numProcesses = 1;
  147.     }
  148.     /* Confirm blocksize is multiple of and less than transfersize*/
  149.     if(blocksize > transfersize){
  150.         fprintf(stderr, "blocksize can not exceed transfersize\n");
  151.         exit(EXIT_FAILURE);
  152.     }
  153.     if(transfersize % blocksize){
  154.         fprintf(stderr, "blocksize must be multiple of transfersize\n");
  155.         exit(EXIT_FAILURE);
  156.     }
  157.     /* Allocate buffer space */
  158.     buffersize = blocksize;
  159.     if(!(transferBuffer = malloc(buffersize*sizeof(*transferBuffer)))){
  160.         perror("Failed to allocate transfer buffer");
  161.         exit(EXIT_FAILURE);
  162.     }
  163.         /* Set new scheduler policy */
  164. /*    fprintf(stdout, "Current Scheduling Policy: %d\n", sched_getscheduler(0));
  165.     fprintf(stdout, "Setting Scheduling Policy to: %d\n", policy);
  166.     if(sched_setscheduler(0, policy, &param)){
  167.     printf("sched_setscheduler(0, policy, &param) is:%d\n", sched_setscheduler(0, policy, &param));
  168.         perror("Error setting scheduler policy");
  169.         exit(EXIT_FAILURE);
  170.     }
  171.     fprintf(stdout, "New Scheduling Policy: %d\n", sched_getscheduler(0));
  172. */
  173.         for(= 0; i< numProcesses; i++){
  174.                 id = fork();
  175.                 printf("id is %d\n", id);
  176.                 if(id == 0){
  177.                     /* Open Input File Descriptor in Read Only mode */
  178.                     if((inputFD = open(inputFilename, O_RDONLY | O_SYNC)) < 0){
  179.                         perror("Failed to open input file");
  180.                         exit(EXIT_FAILURE);
  181.                     }
  182.                     /* Open Output File Descriptor in Write Only mode with standard permissions*/
  183.                     rv = snprintf(outputFilename, MAXFILENAMELENGTH, "%s-%d",
  184.                                   outputFilenameBase, getpid());    
  185.                     if(rv > MAXFILENAMELENGTH){
  186.                         fprintf(stderr, "Output filenmae length exceeds limit of %d characters.\n",
  187.                                 MAXFILENAMELENGTH);
  188.                         exit(EXIT_FAILURE);
  189.                     }
  190.                     else if(rv < 0){
  191.                         perror("Failed to generate output filename");
  192.                         exit(EXIT_FAILURE);
  193.                     }
  194.                     if((outputFD =
  195.                         open(outputFilename,
  196.                              O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
  197.                              S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)) < 0){
  198.                                 perror("Failed to open output file");
  199.                                 exit(EXIT_FAILURE);
  200.                     }
  201.                     /* Print Status */
  202.                     fprintf(stdout, "Reading from %s and writing to %s\n",
  203.                             inputFilename, outputFilename);
  204.                         /* Read from input file and write to output file*/
  205.                     do{
  206.                                 /* Read transfersize bytes from input file*/
  207.                                 bytesRead = read(inputFD, transferBuffer, buffersize);
  208.                                 if(bytesRead < 0){
  209.                                     perror("Error reading input file");
  210.                                     exit(EXIT_FAILURE);
  211.                                 }
  212.                                 else{
  213.                                     totalBytesRead += bytesRead;
  214.                                     totalReads++;
  215.                                 }
  216.                                
  217.                                 /* If all bytes were read, write to output file*/
  218.                                 if(bytesRead == blocksize){
  219.                                     bytesWritten = write(outputFD, transferBuffer, bytesRead);
  220.                                     if(bytesWritten < 0){
  221.                                         perror("Error writing output file");
  222.                                         exit(EXIT_FAILURE);
  223.                                     }
  224.                                     else{
  225.                                         totalBytesWritten += bytesWritten;
  226.                                         totalWrites++;
  227.                                     }
  228.                                 }
  229.                                 /* Otherwise assume we have reached the end of the input file and reset */
  230.                                 else{
  231.                                     if(lseek(inputFD, 0, SEEK_SET)){
  232.                                         perror("Error resetting to beginning of file");
  233.                                         exit(EXIT_FAILURE);
  234.                                     }
  235.                                     inputFileResets++;
  236.                                 }
  237.                        
  238.                     }while(totalBytesWritten < transfersize);
  239.                     /* Output some possibly helpfull info to make it seem like we were doing stuff */
  240.                     fprintf(stdout, "Read:    %zd bytes in %d reads\n",
  241.                             totalBytesRead, totalReads);
  242.                     fprintf(stdout, "Written: %zd bytes in %d writes\n",
  243.                             totalBytesWritten, totalWrites);
  244.                     fprintf(stdout, "Read input file in %d pass%s\n",
  245.                             (inputFileResets + 1), (inputFileResets ? "es" : ""));
  246.                     fprintf(stdout, "Processed %zd bytes in blocks of %zd bytes\n",
  247.                             transfersize, blocksize);
  248.                    
  249.             /* Free Buffer */
  250.                     free(transferBuffer);
  251.                     /* Close Output File Descriptor */
  252.                     if(close(outputFD)){
  253.                         perror("Failed to close output file");
  254.                         exit(EXIT_FAILURE);
  255.                     }
  256.             /* Close Input File Descriptor */
  257.             if(close(inputFD)){
  258.                 perror("Failed to close input file");
  259.                 exit(EXIT_FAILURE);
  260.             }
  261.         break;
  262.         }
  263.         else if(id > 0){ //parent
  264.                 printf("Parent is %d\n", id);
  265.                 int status = 0;
  266.         waitpid(id, &status, 0);
  267.         }
  268.         else{ //error
  269.                 printf("Error. pid %d is negative\n", id );
  270.         }
  271.                 }
  272.     return EXIT_SUCCESS;
  273. }


Learn More :