/* * === FUNCTION ============================================================== * Name: get_device_id * * Description: Calls `djtgcfg enum` and looks for device username. Prompts * for user input if more than one device. Exits with error if * no devices found or djtgcfg is not installed. * * Version: 0.0.1 * Params: Device *device * Returns: void * Usage: get_device_id(Device *device) * Outputs: N/A * * Notes: * ============================================================================= */ void get_device_id(Device *device) { char *tmp; char* args[3]; char output[80]; char* combined; int pipe_id, exit_status, device_id_len; FILE *input; pipe_id = pipe_and_fork(); if (childPid == 0) { // Child process args[0] = "djtgcfg"; args[1] = "enum"; args[2] = (char*) 0; execvp("djtgcfg", args); // Should never happen normally exit(999); } else { // Parent process input = fdopen(pipe_id, "r"); combined = (char*) malloc(80); while (fgets(output, 80, input) != NULL) { combined = (char *) realloc(combined, strlen(combined) + 1 + strlen(output)); combined = strcat(combined, output); } wait(&exit_status); childPid = 0; } // No devices if (strstr(combined, "No devices found") != NULL) { printf("%s\n", "Failed to find device"); } else { // Extract the device user name tmp = strstr(combined, "Device: "); device_id_len = strchr(tmp, '\n') - tmp - 8; device->id = (char *) malloc(device_id_len); strncpy(device->id, tmp + 8, device_id_len); } free(combined); close(pipe_id); }
/* * === FUNCTION ============================================================== * Name: get_device_index * * Description: Calls `djtgcfg init` and looks for device indexes. Prompts * for user input if more than one index. Exits with error if * no devices found or djtgcfg is not installed. * * Version: 0.0.1 * Params: Device *device * Returns: Device index from djtgcfg init * Usage: get_device_index(Device *device) * Outputs: N/A * * Notes: * ============================================================================= */ void get_device_index(Device *device) { char* tmp, *cmp; char* args[5]; char output[80]; char* combined; int pipe_id, exit_status, i, response; FILE *input; pipe_id = pipe_and_fork(); if (childPid == 0) { // Child process args[0] = "djtgcfg"; args[1] = "init"; args[2] = "-d"; args[3] = device->id; args[4] = (char*) 0; execvp("djtgcfg", args); // Should never happen normally exit(999); } else { // Parent process input = fdopen(pipe_id, "r"); combined = (char*) malloc(80); while (fgets(output, 80, input) != NULL) { combined = (char *) realloc(combined, strlen(combined) + 1 + strlen(output)); combined = strcat(combined, output); } wait(&exit_status); childPid = 0; } cmp = malloc(22); for (i = 1; i < 1000; i++) { sprintf(cmp, "Found %d device(s):", i); tmp = strstr(combined, cmp); if (tmp != NULL) break; } free(cmp); free(combined); close(pipe_id); if (tmp == NULL) { printf("%s\n", "No indexes found. Is device switched on?"); exit(5); } printf("%s", tmp); response = -1; while (response < 0 || response > i - 1) { printf("Which device would you like to program?: [0] "); tmp = fgets(output, 80, stdin); response = atoi(output); } device->index = (char *) malloc(strlen(output) + 1); strcpy(device->index, output); // Remove \n char for (int i = 0; i <= strlen(device->index); i++) { if (device->index[i] == '\n') device->index[i] = '\0'; } if (device->index[0] == 0) device->index[0] = '0'; }
/** * DESCRIPTION: * * Prints a promt to the screen. Reads a command line of the following format from the the user: * * cmd0 -a00 -b01 ... -z0n | cmd1 | cmd2 | ... | cmdN -an0 ... -znn * * For each command, the fork_and_pipe() function is called with the * appropiate argv and relative position of the command. * * NOTE: * * You only have to add code at the end of main, see TODO comment. */ int main() { // Allocate a buffer for the command line read from the user. char line_buffer[COMMAND_LINE_BUFFER_SIZE]; // We parse the command line using the next_command() parser. The // parser will populate the following array with the result of each call // to the parse. char* argv[MAX_ARGV_SIZE]; // Count the number of non empty command lines. int line_nr = 0; // Position of each command in a command line. enum cmd_pos pos; // {single, first, middle, last} // Pipe read descriptor to the pipe to the "left". int left_pipe_read_fd = -1; // Count the number of children forked for each command line. int children = 0; while(1) { do { // Print the command prompt including the command line counter. printf(" %d> ", line_nr); fflush(NULL); // Read input from the user. if ( fgets(line_buffer, COMMAND_LINE_BUFFER_SIZE, stdin) == NULL) { perror("====== ERROR ====> READING COMMAND LINE FAILED :("); exit(EXIT_FAILURE); } // Exit if the user types "exit" and presses enter. if (strcmp(line_buffer, "exit\n") == 0) { printf(" Goodbye!\n"); exit(EXIT_SUCCESS); } // If the user presses enter without typing anything else, don't // update the command line counter, just start over again. } while (empty_line(line_buffer)); // We got some input from the user. line_nr++; // Parse the command line do { pos = next_command(line_buffer, argv); // After the call to the next_command() parser function, the // command possition within the command line is now available in the pos // varialble. DBG("\n%6s command %s\n", pos2str(pos), argv[0]); // Loop through the argv and print the command data. int i = 0; while (argv[i] != NULL) { DBG(" argv[%d] @ [0x%x] = \"%s\"\n", i, (unsigned int) argv[i], argv[i]); i++; } // Create a pipe fork a new process for the command. We also // must remember the read descriptor to the new pipe. This // descriptor will become the read descriptor to the pipe to the // "left" for the next command (if any). left_pipe_read_fd = pipe_and_fork(pos, argv, left_pipe_read_fd); children++; // When are we done? } while (pos != single && pos != last); DBG("\nAfter calling next_command(), line [0x%X] ==>%s<==\n", (unsigned int) &line_buffer, line_buffer); // The parent goes here after after all children have been // created for the command. // TODO: Make sure shell doesn't print a new prompt until // all the command processes (children) have terminated. while(children>0){ wait(NULL); children--; } } // end while(1) } // end of main()
/* * === FUNCTION ============================================================== * Name: run_test * * Description: Flexible method for running tests on the ccsrch suite * * LOG FILE TESTS - Format: SELF_LOG * Verifies that the modified ccsrch successfully detects * its own log file regardless of path * Directory scanned: ./tests * Log file outputs: * ./tests/log.log * tests/../tests/log.log * tests/log.log * log.log * * Tests absolute paths, relative with redundancy, relative, * symlinks and no log file output * * IMAGE FILE TESTS - Format: IMAGE * Verifies that the modified ccsrch successfully detects * and skips image files * Files scanned: tests/img.jpg * tests/img.png * tests/img.gif * tests/img.not_an_image_extension * tests/not_an_image.jpg * * SEPARATOR TESTS - Format: SKIPCHARS * Verifies that the modified ccsrch successfully detects and * ignores the default ignore characters * Tests, in order: * space * \n * \r * - * combination of above * * There should be 3 credit card matches in the given file * out of 6 potential PANs * * COMPRESSION TESTS - Format: ZIP * Verifies that the modified ccsrch successfully detects, * unpacks and parses compressed files. * Tests, in order: * tar.gzip * mac os zip file * zip file * zip file containing zip files * * PDF TESTS - Format: PDF * Verifies that the modified ccsrch successfully detects, * unpacks and parses PDF Documents. * * .xlsx TESTS - Format: MS_EXCELX * Verifies that the modified ccsrch successfully detects, * unpacks and parses xlsx documents. * * .docx TESTS - Format: MS_WORDX * Verifies that the modified ccsrch successfully detects, * unpacks and parses docx documents. * * ODS TESTS - Format: ODS * Verifies that the modified ccsrch successfully detects, * unpacks and parses ODS and OTS Open Document Spreadsheet * formatted documents. * Tests, in order: * ods.ods * ots.ots * * ODT TESTS - Format: ODT * Verifies that the modified ccsrch successfully detects, * unpacks and parses ODT and OTT Open Document formatted * documents. * Tests, in order: * odt.odt * ott.ott * * BINARY TESTS - FormatL BINARY * Verifies that AUDIO, VIDEO, EXECUTABLE and BINARY types * are skipped appropriately. * Tests, in order: * ogv.ogv * mp3.mp3 * ccsrch.o * ccsrch * * Version: 0.0.1 * Params: FILE *output * file_type type * Returns: void * Usage: run_test( FILE *output, file_type type ) * Outputs: Test results for given format * ============================================================================= */ void run_test(FILE *output, file_type type) { int num_tests, loop_count; char buffer[80], **test_files, **expected_results; int i, pipe; pid_t pid; FILE *in_out; bool found; // Test counts switch (type) { case SELF_LOG: case ZIP: case BINARY: num_tests = 4; break; case IMAGE: case SKIPCHARS: num_tests = 5; break; case PDF: case MS_EXCELX: case MS_WORDX: num_tests = 1; break; case ODS: case ODT: num_tests = 2; break; } // Initialise as empty strings. 2D memset test_files = malloc(sizeof(char*) * num_tests); expected_results = malloc(sizeof(char*) * num_tests); for ( i = 0; i < num_tests; i++ ) { test_files[i] = malloc(MAXPATH); expected_results[i] = malloc(MAXPATH); memset(test_files[i], '\0', MAXPATH); memset(expected_results[i], '\0', MAXPATH); } // Files and expected outputs switch (type) { case SELF_LOG: strncpy(test_files[0], "./tests/log.log", MAXPATH); /* Absolute path (as best we can) */ strncpy(test_files[1], "tests/../tests/log.log", MAXPATH); /* Weird path */ strncpy(test_files[2], "tests/log.log", MAXPATH); /* Relative path */ strncpy(test_files[3], "tests/log_symlink", MAXPATH); /* Symlink test */ for ( i = 0; i < num_tests; i++ ) strncpy(expected_results[i], "Skipping log file: ", MAXPATH); break; case IMAGE: strncpy(test_files[0], "tests/img.jpg", MAXPATH); strncpy(test_files[1], "tests/img.png", MAXPATH); strncpy(test_files[2], "tests/img.gif", MAXPATH); strncpy(test_files[3], "tests/img.not_an_image_extension", MAXPATH); strncpy(test_files[4], "tests/not_an_image.jpg", MAXPATH); for ( i = 0; i < num_tests - 1; i++ ) strncpy(expected_results[i], "Binary types skipped ->\t\t1", MAXPATH); strncpy(expected_results[4], "Binary types skipped ->\t\t0", MAXPATH); break; case BINARY: strncpy(test_files[0], "tests/ogv.ogv", MAXPATH); strncpy(test_files[1], "tests/mp3.mp3", MAXPATH); strncpy(test_files[2], "tests/ccsrch.o", MAXPATH); strncpy(test_files[3], "tests/ccsrch", MAXPATH); for ( i = 0; i < num_tests - 1; i++ ) strncpy(expected_results[i], "Binary types skipped ->\t\t1", MAXPATH); break; case SKIPCHARS: strncpy(test_files[0], "tests/ignore_space.txt", MAXPATH); strncpy(test_files[1], "tests/ignore_unix_newline.txt", MAXPATH); strncpy(test_files[2], "tests/ignore_windows_newline.txt", MAXPATH); strncpy(test_files[3], "tests/ignore_dash.txt", MAXPATH); strncpy(test_files[4], "tests/ignore_combination.txt", MAXPATH); for ( i = 0; i < num_tests; i++ ) strncpy(expected_results[i], "Credit card matches ->\t\t3", MAXPATH); break; case ZIP: strncpy(test_files[0], "tests/tartest.tar.gz", MAXPATH); strncpy(test_files[1], "tests/test.mac.zip", MAXPATH); strncpy(test_files[2], "tests/test.zip", MAXPATH); strncpy(test_files[3], "tests/test2.zip", MAXPATH); strncpy(expected_results[0], "Credit card matches ->\t\t9", MAXPATH); strncpy(expected_results[1], "Credit card matches ->\t\t30", MAXPATH); strncpy(expected_results[2], "Credit card matches ->\t\t30", MAXPATH); strncpy(expected_results[3], "Credit card matches ->\t\t15", MAXPATH); break; case PDF: strncpy(test_files[0], "tests/pdf.pdf", MAXPATH); strncpy(expected_results[0], "Credit card matches ->\t\t15", MAXPATH); break; case MS_EXCELX: strncpy(test_files[0], "tests/xlsx.xlsx", MAXPATH); strncpy(expected_results[0], "Credit card matches ->\t\t3", MAXPATH); break; case MS_WORDX: strncpy(test_files[0], "tests/docx.docx", MAXPATH); strncpy(expected_results[0], "Credit card matches ->\t\t3", MAXPATH); break; case ODS: strncpy(test_files[0], "tests/ods.ods", MAXPATH); strncpy(test_files[1], "tests/ots.ots", MAXPATH); for ( i = 0; i < num_tests; i++ ) strncpy(expected_results[i], "Credit card matches ->\t\t3", MAXPATH); break; case ODT: strncpy(test_files[0], "tests/odt.odt", MAXPATH); strncpy(test_files[1], "tests/ott.ott", MAXPATH); for ( i = 0; i < num_tests; i++ ) strncpy(expected_results[i], "Credit card matches ->\t\t3", MAXPATH); break; } // Loop counts switch (type) { case SELF_LOG: loop_count = num_tests + 1; break; default: loop_count = num_tests; } for ( i = 0; i < loop_count; i++ ) { pid = pipe_and_fork(&pipe, true); if (pid == (pid_t) 0) { /* Child */ dup2(pipe, STDOUT_FILENO); dup2(pipe, STDERR_FILENO); // Particulars of the invocation of ccsrch switch (type) { case SELF_LOG: if (i < num_tests) execl("./ccsrch", "ccsrch", "-o", test_files[i], "tests", NULL); else execl("./ccsrch", "ccsrch", "tests", NULL); break; default: execl("./ccsrch", "ccsrch", test_files[i], NULL); } } else if (pid > (pid_t) 0) { /* Parent */ in_out = fdopen(pipe, "r"); found = false; while (!found && in_out != NULL && !feof(in_out)) { fgets(buffer, 80, in_out); // Result checking switch (type) { case SELF_LOG: if (strstr(buffer, expected_results[0]) != NULL) found = true; break; default: if (strstr(buffer, expected_results[i]) != NULL) found = true; } } // Result printing switch (type) { case SELF_LOG: if ((i < num_tests && found) || (i == num_tests && !found)) fprintf(output, "%s", "."); else fprintf(output, "%s", "F"); break; default: if (found) fprintf(output, "%s", "."); else fprintf(output, "%s", "F"); } fflush(output); wait(NULL); close(pipe); } else { /* Fork failed */ fprintf(stderr, "\n%s\n", "Failed to pipe and fork"); } } // Clean up for ( i = 0; i < num_tests; i++ ) { free(test_files[i]); free(expected_results[i]); } free(test_files); free(expected_results); }
/* * === FUNCTION ============================================================== * Name: detect_file_type * * Description: Detects file type of given file and returns true if we should * skip it and false otherwise. * Forks and calls file from command line. Parses result to * determine file type. * * Version: 0.0.1 * Params: char *filename * Returns: bool true if type to skip * bool false otherwise * Usage: detect_file_type( char *filename ) * Outputs: N/A * * Notes: * Open Office mime types from: * http://www.openoffice.org/framework/documentation/mimetypes/mimetypes.html * Image mime types from: * http://www.iana.org/assignments/media-types/image/index.html * ============================================================================= */ file_type detect_file_type(char *filename) { char buffer[80], *pipe_output, full_filename[MAXPATH], *file_cmd_output; int pipe, read_count, fork_count = 0; pid_t pid; file_type type; FILE *in_out; // Default type = UNKNOWN; while (fork_count++ < 2) { pid = pipe_and_fork(&pipe, true); if (pid == (pid_t) 0) { /* Child */ dup2(pipe, STDOUT_FILENO); //dup2(pipe, STDERR_FILENO); /* Remove comment if you need to debug */ full_filename[0] = '\0'; if (filename[0] != '/') strncat(full_filename, pwd, MAXPATH - strlen(full_filename)); strncat(full_filename, filename, MAXPATH - strlen(full_filename)); if (fork_count == 1) execlp("file", "file", "--mime", "-b", full_filename, NULL); else execlp("file", "file", "-b", full_filename, NULL); // Exec failed #ifdef DEBUG perror("detect_file_type: failed to execlp \"file\""); #endif close(pipe); exit(errno); } else if (pid > (pid_t) 0) { /* Parent */ in_out = fdopen(pipe, "r"); file_cmd_output = malloc(80); file_cmd_output[0] = '\0'; read_count = 1; while (in_out != NULL && !feof(in_out)) { pipe_output = fgets(buffer, 80, in_out); if (pipe_output != NULL) { file_cmd_output = realloc(file_cmd_output, strlen(file_cmd_output) + strlen(pipe_output) + 1); strncat(file_cmd_output, pipe_output, 80); } } // Work out what it is if (file_cmd_output != NULL) { if (strstr(file_cmd_output, "text/plain") != NULL) type = ASCII; else if (strstr(file_cmd_output, "application/x-executable") != NULL || strstr(file_cmd_output, "executable") != NULL || strstr(file_cmd_output, "relocatable") != NULL) type = EXECUTABLE; else if (strstr(file_cmd_output, "image/") != NULL || strstr(file_cmd_output, "image data") != NULL) type = IMAGE; else if (strstr(file_cmd_output, "video/") != NULL || strstr(file_cmd_output, "video") != NULL || strstr(file_cmd_output, "AVI") != NULL || strstr(file_cmd_output, "MPEG") != NULL) type = VIDEO; else if (strstr(file_cmd_output, "audio/") != NULL || strstr(file_cmd_output, "application/octet-stream") != NULL || strstr(file_cmd_output, "Audio file") != NULL) type = AUDIO; else if (strstr(file_cmd_output, "application/x-tar") != NULL) type = TAR; else if (strstr(file_cmd_output, "application/zip") != NULL) { // Due to poor msword filetype detection, we need to rely on // file extensions here if (strncmp(last_strstr(filename, "."), ".docx", 7) == 0) type = MS_WORDX; else if (strncmp(last_strstr(filename, "."), ".xlsx", 7) == 0) type = MS_EXCELX; else // Make ZIP the default here type = ZIP; } else if (strstr(file_cmd_output, "application/x-gzip") != NULL) type = GZIP; else if (strstr(file_cmd_output, "application/xml") != NULL) type = XML; else if (strstr(file_cmd_output, "application/pdf") != NULL) type = PDF; else if (strstr(file_cmd_output, "opendocument.text-template") != NULL) type = OTT; else if (strstr(file_cmd_output, "opendocument.text") != NULL) type = ODT; else if (strstr(file_cmd_output, "opendocument.spreadsheet.template") != NULL) type = OTS; else if (strstr(file_cmd_output, "opendocument.spreadsheet") != NULL) type = ODS; else if (strstr(file_cmd_output, "application/vnd.ms-excel") != NULL) type = MS_EXCEL; else if (strstr(file_cmd_output, "application/vnd.ms-word") != NULL) type = MS_WORD; else if (strstr(file_cmd_output, "application/msword") != NULL || strstr(file_cmd_output, "application/vnd.ms-office") != NULL) { // Due to poor msword filetype detection, we need to rely on // file extensions here if (strncmp(last_strstr(filename, "."), ".doc", 6) == 0) type = MS_WORD; else if (strncmp(last_strstr(filename, "."), ".xls", 6) == 0) type = MS_EXCEL; else // Make MS_WORD the default here type = MS_WORD; } // This should stay last. Other legitimate mime types often use this charset else if (fork_count == 2 && strstr(file_cmd_output, "binary") != NULL) type = BINARY; else type = UNKNOWN; } // Clean up wait(NULL); close(pipe); free(file_cmd_output); #ifdef DEBUG } else { /* Fork failed */ fprintf(stderr, "\n%s\n", "Failed to pipe and fork"); #endif } // Only check again if we didn't know what it was if (type != UNKNOWN) break; } return type; }