Multithreading a password checker in C - c

Currently attempting to get this program to use multithreading using pthread_create, pthread_join, pthread_exit, and pthread_self. I then intend to use crypt_r in place of crypt in my code.
It will only be able to go up to 8 threads, but I don't even know how to get started with two. I just have one line that declares pthread_t t1,t2,t3,t4,t5,t6,t7,t8.
The plan with these is to put them in to pthread_create but besides initializing these values, I don't know where to go from here.
I know that pthread_create's input would be something like pthread_create(t1, NULL, ... , ...) but I do not know how to go about making the 3rd input or what the 4th input even is.
I then have to make sure to split up the range of letters that each thread is checking based on the number of threads specified by a command line arg. I've designed this so far to work on one thread only, planning on moving it to crypt_r with multithreading...
Really confused as to how I could get to make this work.. If possible.
I know some sort of void function is the third entry in to pthread_create.. but does that function have to be what my passwordChecker is? Or what?
/*
crack.exe
*/
/* g++ -o crack crack.c -lcrypt -lpthread */
//#define _GNU_SOURCE
#include <crypt.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
void *passwordLooper(int ks, char target[9], char s[10]);
void *threadFunction(void *threads);
int main(int argc, char *argv[]){ /* usage = crack threads keysize target */
int i = 0;
/* arg[0] = crack, arg[1] = #of threads arg[2] = size of password, arg[3] = hashed password being cracked */
if (argc != 4) {
fprintf(stderr, "Too few/many arguements give.\n");
fprintf(stderr, "Proper usage: ./crack threads keysize target\n");
exit(0);
}
int threads = *argv[1]-'0'; // threads is now equal to the second command line argument number
int keysize = *argv[2]-'0'; // keysize is now equal to the third command line argument number
char target[9];
strcpy(target, argv[3]);
char salt[10];
while ( i < 2 ){ //Takes first two characters of the hashed password and assigns them to the salt variable
salt[i] = target[i];
i++;
}
printf("threads = %d\n", threads); /*used for testing */
printf("keysize = %d\n", keysize);
printf("target = %s\n", target);
printf("salt = %s\n", salt);
if (threads < 1 || threads > 8){
fprintf(stderr, "0 < threads <= 8\n");
exit(0);
} /*Checks to be sure that threads and keysize are*/
if (keysize < 1 || keysize > 8){ /*of the correct size */
fprintf(stderr, "0 < keysize <= 8\n");
exit(0);
}
pthread_t t1,t2,t3,t4,t5,t6,t7,t8;
if ( threads = 1 ){
pthread_create(&t1, NULL, *threadFunction, threads);
}
char unSalted[30];
int j = 0;
for (i = 2; target[i] != '\0'; i++){ /*generates variable from target that does not include salt*/
unSalted[j] = target[i];
j++;
}
printf("unSalted = %s\n", unSalted); //unSalted is the variable target without the first two characters (the salt)
char password[9] = {0};
passwordLooper(keysize, target, salt);
}
/*_____________________________________________________________________________________________________________*/
/*_____________________________________________________________________________________________________________*/
void *passwordLooper(int ks, char target[9], char s[10]){
char password[9] = {0};
struct crypt_data cd;
cd.initialized = 0;
int result;
for (;;){
int level = 0;
while (level < ks && strcmp( crypt(password, s), target ) != 0) {
if (password[level] == 0){
password[level] = 'a';
break;
}
if (password[level] >= 'a' && password[level] < 'z'){
password[level]++;
break;
}
if (password[level] == 'z'){
password[level] = 'a';
level++;
}
}
char *cryptPW = crypt(password, s);
result = strcmp(cryptPW, target);
if (result == 0){ //if result is zero, cryptPW and target are the same
printf("result = %d\n", result);
printf ("Password found: %s\n", password);
printf("Hashed version of password is %s\n", cryptPW);
break;
}
if (level >= ks){ //if level ends up bigger than the keysize, break, no longer checking for passwords
printf("Password not found\n");
break;
}
}
return 0;
}
With malloc'd structs
/*
crack.exe
By: Zach Corse
*/
/* g++ -o crack crack.c -lcrypt -lpthread */
//#define _GNU_SOURCE
#include <crypt.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
void *passwordLooper(void *passwordData);
//void *threadFunction(void *threads);
typedef struct{
int keysize;
char *target;
char *salt;
}passwordData;
int main(int argc, char *argv[]){ /* usage = crack threads keysize target */
int i = 0;
/* arg[0] = crack, arg[1] = #of threads arg[2] = size of password, arg[3] = hashed password being cracked */
if (argc != 4) {
fprintf(stderr, "Too few/many arguements give.\n");
fprintf(stderr, "Proper usage: ./crack threads keysize target\n");
exit(0);
}
int threads = *argv[1]-'0'; // threads is now equal to the second command line argument number
int keysize = *argv[2]-'0'; // keysize is now equal to the third command line argument number
char target[9];
strcpy(target, argv[3]);
char salt[10];
while ( i < 2 ){ //Takes first two characters of the hashed password and assigns them to the salt variable
salt[i] = target[i];
i++;
}
printf("threads = %d\n", threads); /*used for testing */
printf("keysize = %d\n", keysize);
printf("target = %s\n", target);
printf("salt = %s\n", salt);
if (threads < 1 || threads > 8){
fprintf(stderr, "0 < threads <= 8\n");
exit(0);
} /*Checks to be sure that threads and keysize are*/
if (keysize < 1 || keysize > 8){ /*of the correct size */
fprintf(stderr, "0 < keysize <= 8\n");
exit(0);
}
pthread_t t1,t2,t3,t4,t5,t6,t7,t8;
struct crypt_data data;
data.initialized = 0;
//~ passwordData.keysize = keysize;
//~ passwordData.target = target;
//~ passwordData.salt = salt;
passwordData *pwd = (passwordData *) malloc(sizeof(pwd));
pwd->keysize = keysize;
pwd->target = target;
pwd->salt = salt;
//~ if ( threads = 1 ){
//~ pthread_create(&t1, NULL, *threadFunction, threads);
//~ }
char unSalted[30];
int j = 0;
for (i = 2; target[i] != '\0'; i++){ /*generates variable from target that does not include salt*/
unSalted[j] = target[i];
j++;
}
printf("unSalted = %s\n", unSalted); //unSalted is the variable target without the first two characters (the salt)
char password[9] = {0};
passwordLooper(pwd);
}
/*_____________________________________________________________________________________________________________*/
/*_____________________________________________________________________________________________________________*/
void *passwordLooper(passwordData pwd){
char password[9] = {0};
int result;
int ks = pwd.keysize;
char *target = pwd.target;
char *s = pwd.salt;
for (;;){
int level = 0;
while (level < ks && strcmp( crypt(password, s), target ) != 0) {
if (password[level] == 0){
password[level] = 'a';
break;
}
if (password[level] >= 'a' && password[level] < 'z'){
password[level]++;
break;
}
if (password[level] == 'z'){
password[level] = 'a';
level++;
}
}
char *cryptPW = crypt(password, s);
result = strcmp(cryptPW, target);
if (result == 0){ //if result is zero, cryptPW and target are the same
printf("result = %d\n", result);
printf ("Password found: %s\n", password);
printf("Hashed version of password is %s\n", cryptPW);
break;
}
if (level >= ks){ //if level ends up bigger than the keysize, break, no longer checking for passwords
printf("Password not found\n");
break;
}
}
return 0;
}

Well, here's the prototype for pthread_create:
int
pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,
void *(*start_routine)(void *), void *restrict arg);
It shows that the 3rd arg is a pointer to a function that returns a pointer to void and takes a pointer to void as its sole argument. I see you have a prototype for:
void *threadFunction(void *threads);
which meets those specifications, but it's not actually written? The 4th argument in pthread_create is just a pointer to void, which can essentially contain anything you want it to.
I'm guessing that the function you want to thread is actually passwordLooper, which takes 3 arguments.. but pthread_create specifies a function that takes only 1. You have to find a workaround so that you can only accept a single argument to your passwordLooper function yet still pass all 3 variables that you care about. There are a few ways this can be done:
Global variables (yuck, not thread safe, don't really do this)
malloc() some memory, memcpy() your arguments into it (or pointers to them), and pass that newly malloc()ed memory to pthread_create(). In your called function you'll have to parse the 3 variables back out of the void * (hacky, but works in theory)
Define a struct that contains your 3 arguments, malloc a copy of that struct, copy your variables into the newly malloced struct, and pass it as your 4th argument. This greatly simplifies parsing the values back out and is the general way to accomplish passing multiple variables as pthread_create's 4th argument

Related

qsort dynamic 2d char array with alphanumeric filenames - C program

I'm new here, so this is my first post. I've been struggling for 2 weeks to solve this problem. I'm trying to open a directory, capture and store the names of the files found, sort them in ascending order, and print the results. My issue is either qsort causes my program to crash entirely, or qsort doesn't sort the array at all because the files are alphanumeric. I even tried looping through a stored filename to output each character, just to see if I could eventually try comparing the characters between two array locations for sorting. But I noticed that it can't seem to see or recognize the numbers in the alphanumeric filename (for example: "f1.jpg" will only print "f", a blank, then "j", and that's it. I should note that I cannot change the file names because I don't know in advance the names or total files. I'm trying to make this to be dynamic. The following is the main code that I'm having problems with since it crashes at the 'qsort' keyword:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>
#include <dirent.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int compare(const void *a, const void *b);
void readInFilenames();
int main
{
readInFilenames();
system("pause");
}
int compare(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
void readInFilenames()
{
char cwd[1024];
DIR *dir = NULL;
struct dirent *pent = NULL;
struct stat info;
char file_path[50] = "files/";
int total_files = 0;
int file_size;
// Change directory to file location
chdir(file_path);
if((getcwd(cwd, sizeof(cwd))) != NULL)
{
printf("Current Directory: %s\n", cwd);
}
// Open directory and count the total number of files found
dir = opendir(cwd);
if(dir != NULL)
{
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
total_files++;
file_size = sizeof(pent->d_name);
}
}
}
}
printf("# of files found: %d\n", total_files);
rewinddir(dir); //reset pointer back to beginning of file directory
// Create character array to store file names;
char *filenames_arr[total_files][file_size];
int size = sizeof(filenames_arr)/sizeof(filenames_arr[total_files]);
total_files = 0; //reset file counter back to 0;
// Read and store file names in the character array
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
strcpy(filenames_arr[total_files], pent->d_name);
//printf("%s\n", filenames_arr[i]);
total_files++;
}
}
}
}
closedir(dir);
// Print original array contents
printf("Original List of Files\n");
printf("----------------------\n");
for(int i = 0; i < total_files; i++)
{
printf("%s\n", filenames_arr[i]);
}
// Sort array in ascending order
qsort(filenames_arr, total_files, size, compare);
//qsort(filenames_arr, total_files, sizeof(filenames_arr[0]), (char (*)(const void*, const void*))strcmp);
// Print organized array contents
printf("Sorted List of Files\n");
printf("----------------------\n");
for(int i = 0; i < total_files; i++)
{
printf("%s\n", filenames_arr[i]);
}
printf("\nFinished!\n");
}
}
This portion of code is when I was trying to print each individual characters. This was originally located where the final array printing takes place in the previous code:
int i = 0;
int j = 0;
while(i < total_files)
{
printf("File Name: %s\n", filenames_arr[i]);
printf("String Length: %d\n", strlen(filenames_arr[i]));
while(filenames_arr[i] != '\0')
{
printf("Checking filenames_arr[%d][%d]\n", i, j);
if(isalpha((unsigned char)filenames_arr[i][j]) != 0)
{
printf("In isalpha\n");
printf("Found: %c\n", filenames_arr[i][j]);
}
else if(isdigit((unsigned char)filenames_arr[i][j]) != 0)
{
printf("In isdigit\n");
printf("Found: %d\n", filenames_arr[i][j]);
}
j++;
}
printf("-------------------------------------------\n");
i++;
j = 0;
}
How do I sort a 2D array of alphanumeric character strings using qsort? What is it about qsort, or even my array setup that's causing my program to crash? Also, how does qsort work? I've tried searching forums and online course notes to find out whether or not qsort only sorts by looking just at the first character, all characters, or if it has problems with numbers. Thank you in advance!
UPDATE:
I made the following edits to my code. Its working much better, in that qsort no longer crashes program. But, qsort still isn't sorting. Here are the updates I made, followed by a screenshot of the results:
typedef struct{
char *filename;
}filedata;
int compare(const void *a, const void *b);
void readInFilenames();
int main(void){
readInFilenames();
system("pause");
}
int compare (const void *a, const void *b ) {
filedata *ia = (filedata *)a;
filedata *ib = (filedata *)b;
return strcmp(ia->filename, ib->filename);
}
readInFilenames(){
.
.
.
printf("# of files found: %d\n", total_files);
rewinddir(dir);
filedata fn_data[total_files];
total_files = 0;
printf("Original Array: \n");
while((pent = readdir(dir)) != NULL)
{
.
.
.
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
fn_data[total_files].filename = malloc(file_size + 1);
strcpy(fn_data[total_files].filename, pent->d_name);
printf("%s\n", fn_data[total_files].filename);
total_files++;
}
}
closedir(dir);
printf("\n");
qsort(fn_data, total_files, sizeof(filedata), compare);
printf("Sorted Array:\n");
for(int i = 0; i < total_files; i++)
printf("%s\n", fn_data[i].filename);
printf("Finished!\n");
}
Click here to see sorting results
The list should print: f0.dat, f1.dat, f2.dat, f3.dat,...,f20.dat. But instead it prints: f0.dat, f1.dat, f10.dat, f11.dat,...,f9.dat.
OP has fixed code to cope with "qsort dynamic 2d char array with filenames" by enabling warnings and using #Snohdo advice.
Yet code is still doing a compare with strcmp() which only treat digits as characters and not numerically to achieve f1.dat, f2.dat, f3.dat,...,f20.dat order.
Following is a compare functions that looks for digits to invoke an alternate compare for numeric sub-strings. Variations on this compare can be made by OP to suit detailed coding goals.
int AdamsOrder(const char *s1, const char *s2) {
// Compare as `unsigned char` as that is `strcmp()` behavior. C11 7.24.1 3
const unsigned char *us1 = (const unsigned char *) s1;
const unsigned char *us2 = (const unsigned char *) s2;
while (*us1 && *us2) {
if (isdigit(*us1) && isdigit(*us2)) {
char *end; // dummy
unsigned long long l1 = strtoull(us1, &end, 10); // Parse for a number
unsigned long long l2 = strtoull(us2, &end, 10);
if (l1 > l2) return 1;
if (l1 < l2) return -1;
// Continue on treating as text. OP needs to decide how to handle ties: "0001" vs "1"
}
if (*us1 > *us2) return 1;
if (*us1 < *us2) return -1;
us1++;
us2++;
}
// At this point, at least one string ended (i.e. points to '\0').
// The return statement below will behave as follows:
// If a string ended, *us1/2 will be 0. Let an unfinished one be X > 0.
// First string ended : ( 0 > X ) - ( 0 < X ) = false - true = 0 - 1 = -1
// Second string ended: ( X > 0 ) - ( X < 0 ) = true - false = 1 - 0 = 1
// Both strings ended : ( 0 > 0 ) - ( 0 < 0 ) = false - false = 0 - 0 = 0
return (*us1 > *us2) - (*us1 < *us2);
}

Can't eliminate one character in my array while parsing it even though I handle that character

So this is my second time adapting my code to fscanf to get what I want. I threw some comments next to the output. The main issue I am having is that the one null character or space is getting added into the array. I have tried to check for the null char and the space in the string variable and it does not catch it. I am a little stuck and would like to know why my code is letting that one null character through?
Part where it is slipping up "Pardon, O King," output:King -- 1; -- 1
so here it parses king a word and then ," goes through the strip function and becomes \0, then my check later down the road allows it through??
Input: a short story containing apostrophes and commas (the lion's rock. First, the lion woke up)
//Output: Every unique word that shows up with how many times it shows up.
//Lion -- 1
//s - 12
//lion -- 8
//tree -- 2
//-- 1 //this is the line that prints a null char?
//cub -- //3 it is not a space! I even check if it is \0 before entering
//it into the array. Any ideas (this is my 2nd time)?
//trying to rewrite my code around a fscanf function.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
//Remove non-alpha numeric characters
void strip_word(char* string)
{
char* string_two = calloc(80, sizeof(char));
int i;
int c = 0;
for(i = 0; i < strlen(string); i++)
{
if(isalnum(string[i]))
{
string_two[c] = string[i];
++c;
}
}
string_two[i] = '\0';
strcpy(string, string_two);
free(string_two);
}
//Parse through file
void file_parse(FILE* text_file, char*** word_array, int** count_array, int* total_count, int* unique_count)
{
int mem_Size = 8;
int is_unique = 1;
char** words = calloc(mem_Size, sizeof(char *)); //Dynamically allocate array of size 8 of char*
if (words == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
int* counts = calloc(mem_Size, sizeof(int)); //Dynamically allocate array of size 8 of int
if (counts == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
printf("Allocated initial parallel arrays of size 8.\n");
fflush(stdout);
char* string;
while('A')
{
is_unique = 1;
fscanf(text_file, " ,");
fscanf(text_file, " '");
while(fscanf(text_file, "%m[^,' \n]", &string) == 1) //%m length modifier
{
is_unique = 1;
strip_word(string);
if(string == '\0') continue; //if the string is empty move to next iteration
else
{
int i = 0;
++(*total_count);
for(i = 0; i < (*unique_count); i++)
{
if(strcmp(string, words[i]) == 0)
{
counts[i]++;
is_unique = 0;
break;
}
}
if(is_unique)
{
++(*unique_count);
if((*unique_count) >= mem_Size)
{
mem_Size = mem_Size*2;
words = realloc(words, mem_Size * sizeof(char *));
counts = realloc(counts, mem_Size * sizeof(int));
if(words == NULL || counts == NULL)
{
fprintf(stderr, "ERROR: realloc() failed!");
}
printf("Re-allocated parallel arrays to be size %d.\n", mem_Size);
fflush(stdout);
}
words[(*unique_count)-1] = calloc(strlen(string) + 1, sizeof(char));
strcpy(words[(*unique_count)-1], string);
counts[(*unique_count) - 1] = 1;
}
}
free(string);
}
if(feof(text_file)) break;
}
printf("All done (successfully read %d words; %d unique words).\n", *total_count, *unique_count);
fflush(stdout);
*word_array = words;
*count_array = counts;
}
int main(int argc, char* argv[])
{
if(argc < 2 || argc > 3) //Checks if too little or too many args
{
fprintf(stderr, "ERROR: Invalid Arguements\n");
return EXIT_FAILURE;
}
FILE * text_file = fopen(argv[1], "r");
if (text_file == NULL)
{
fprintf(stderr, "ERROR: Can't open file");
}
int total_count = 0;
int unique_count = 0;
char** word_array;
int* count_array;
file_parse(text_file, &word_array, &count_array, &total_count, &unique_count);
fclose(text_file);
int i;
if(argv[2] == NULL)
{
printf("All words (and corresponding counts) are:\n");
fflush(stdout);
for(i = 0; i < unique_count; i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
else
{
printf("First %d words (and corresponding counts) are:\n", atoi(argv[2]));
fflush(stdout);
for(i = 0; i < atoi(argv[2]); i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
for(i = 0; i < unique_count; i++)
{
free(word_array[i]);
}
free(word_array);
free(count_array);
return EXIT_SUCCESS;
}
I'm not sure quite what's going wrong with your code. I'm working on macOS Sierra 10.12.3 with GCC 6.3.0, and the local fscanf() does not support the m modifier. Consequently, I modified the code to use a fixed size string of 80 bytes. When I do that (and only that), your program runs without obvious problem (certainly on the input "the lion's rock. First, the lion woke up").
I also think that the while ('A') loop (which should be written conventionally while (1) if it is used at all) is undesirable. I wrote a function read_word() which gets the next 'word', including skipping blanks, commas and quotes, and use that to control the loop. I left your memory allocation in file_parse() unchanged. I did get rid of the memory allocation in strip_word() (eventually — it worked OK as written too).
That left me with:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
static void strip_word(char *string)
{
char string_two[80];
int i;
int c = 0;
int len = strlen(string);
for (i = 0; i < len; i++)
{
if (isalnum(string[i]))
string_two[c++] = string[i];
}
string_two[c] = '\0';
strcpy(string, string_two);
}
static int read_word(FILE *fp, char *string)
{
if (fscanf(fp, " ,") == EOF ||
fscanf(fp, " '") == EOF ||
fscanf(fp, "%79[^,' \n]", string) != 1)
return EOF;
return 0;
}
static void file_parse(FILE *text_file, char ***word_array, int **count_array, int *total_count, int *unique_count)
{
int mem_Size = 8;
char **words = calloc(mem_Size, sizeof(char *));
if (words == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
int *counts = calloc(mem_Size, sizeof(int));
if (counts == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
printf("Allocated initial parallel arrays of size 8.\n");
fflush(stdout);
char string[80];
while (read_word(text_file, string) != EOF)
{
int is_unique = 1;
printf("Got [%s]\n", string);
strip_word(string);
if (string[0] == '\0')
continue;
else
{
int i = 0;
++(*total_count);
for (i = 0; i < (*unique_count); i++)
{
if (strcmp(string, words[i]) == 0)
{
counts[i]++;
is_unique = 0;
break;
}
}
if (is_unique)
{
++(*unique_count);
if ((*unique_count) >= mem_Size)
{
mem_Size = mem_Size * 2;
words = realloc(words, mem_Size * sizeof(char *));
counts = realloc(counts, mem_Size * sizeof(int));
if (words == NULL || counts == NULL)
{
fprintf(stderr, "ERROR: realloc() failed!");
exit(EXIT_FAILURE);
}
printf("Re-allocated parallel arrays to be size %d.\n", mem_Size);
fflush(stdout);
}
words[(*unique_count) - 1] = calloc(strlen(string) + 1, sizeof(char));
strcpy(words[(*unique_count) - 1], string);
counts[(*unique_count) - 1] = 1;
}
}
}
printf("All done (successfully read %d words; %d unique words).\n", *total_count, *unique_count);
fflush(stdout);
*word_array = words;
*count_array = counts;
}
int main(int argc, char *argv[])
{
if (argc < 2 || argc > 3)
{
fprintf(stderr, "ERROR: Invalid Arguements\n");
return EXIT_FAILURE;
}
FILE *text_file = fopen(argv[1], "r");
if (text_file == NULL)
{
fprintf(stderr, "ERROR: Can't open file");
return EXIT_FAILURE;
}
int total_count = 0;
int unique_count = 0;
char **word_array = 0;
int *count_array = 0;
file_parse(text_file, &word_array, &count_array, &total_count, &unique_count);
fclose(text_file);
if (argv[2] == NULL)
{
printf("All words (and corresponding counts) are:\n");
fflush(stdout);
for (int i = 0; i < unique_count; i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
else
{
printf("First %d words (and corresponding counts) are:\n", atoi(argv[2]));
fflush(stdout);
for (int i = 0; i < atoi(argv[2]); i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
for (int i = 0; i < unique_count; i++)
free(word_array[i]);
free(word_array);
free(count_array);
return EXIT_SUCCESS;
}
When run on the data file:
the lion's rock. First, the lion woke up
the output was:
Allocated initial parallel arrays of size 8.
Got [the]
Got [lion]
Got [s]
Got [rock.]
Got [First]
Got [the]
Got [lion]
Got [woke]
Got [up]
All done (successfully read 9 words; 7 unique words).
All words (and corresponding counts) are:
the -- 2
lion -- 2
s -- 1
rock -- 1
First -- 1
woke -- 1
up -- 1
When the code was run on your text, including double quotes, like this:
$ echo '"Pardon, O King,"' | cw37 /dev/stdin
Allocated initial parallel arrays of size 8.
Got ["Pardon]
Got [O]
Got [King]
Got ["]
All done (successfully read 3 words; 3 unique words).
All words (and corresponding counts) are:
Pardon -- 1
O -- 1
King -- 1
$
It took a little finnagling of the code. If there isn't an alphabetic character, your code still counts it (because of subtle problems in strip_word()). That would need to be handled by checking strip_word() more carefully; you test if (string == '\0') which checks (belatedly) whether memory was allocated where you need if (string[0] == '\0') to test whether the string is empty.
Note that the code in read_word() would be confused into reporting EOF if there were two commas in a row, or an apostrophe followed by a comma (though it handles a comma followed by an apostrophe OK). Fixing that is fiddlier; you'd probably be better off using a loop with getc() to read a string of characters. You could even use that loop to strip non-alphabetic characters without needing a separate strip_word() function.
I am assuming you've not yet covered structures yet. If you had covered structures, you'd use an array of a structure such as struct Word { char *word; int count; }; and allocate the memory once, rather than needing two parallel arrays.

ls: cannot access : No such file or directory

When i type ls i get this message twice : ls: cannot access : No such file or directory. But when i type something like that ls -l /tmp or executing a "c" code located in the path everything is fine. Any ideas what is going wrong?
My code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
for (;;) {
char *cmd,*splitcmd,*pr0,*pr1,*pr2;
int i, j, nargc = 0, characters;
char **cmdArray;
size_t bufsize = 1024;
pid_t pid, wpid;
int status = 0;
printf("Type a command : \n");
cmd = (char *) malloc(bufsize * sizeof(char));
characters = getline(&cmd, &bufsize, stdin);
// printf("cmd===> %s characters===> %d \n",cmd,characters);
if (cmd[characters-1] == '\n')
{
cmd[characters-1] = '\0';
characters--;
}
// printf("cmd===> %s characters===> %d \n",cmd,characters);
cmdArray = (char**) malloc(bufsize * sizeof(char *));
for (i = 0 ; i < bufsize ; i++)
{
cmdArray[i] = (char*) malloc(bufsize*sizeof(char));
}
splitcmd = strtok(cmd," ");
// printf(" cmd==== %s\n",cmd);
while ((splitcmd))
{
cmdArray[nargc] = splitcmd;
if (cmdArray[nargc][(strlen(cmdArray[nargc])) - 1] == ' ')
cmdArray[nargc][(strlen(cmdArray[nargc]))-1] == '\0';
// printf(" nargc====%d cmdArray===[ %s ] \n",nargc,cmdArray[nargc]);
nargc++;
pr0 = cmdArray[0];
pr1 = cmdArray[1];
pr2 = cmdArray[2];
splitcmd = strtok(NULL," ");
//printf(" pr0 %s \n",pr0);
//printf(" pr1 %s \n",pr1);
//printf(" pr2 %s \n",pr2);
}
if ((pid = fork()) == 0)
{
char *argv[] = {pr0, pr1, pr2, NULL};
execvp(argv[0],argv);
for (int i = 0; i < 100; i++) {
free(cmdArray[i]);
}
free(cmdArray);
}
wait(&status);
}
}
Your code has a number of problems, many of which are identified by turning on warnings. Use -Weverything if your compiler supports it, or at least -Wall if it does not. However, your particular question is in how you're calling execvp().
char *argv[] = {pr0, pr1, pr2, NULL};
execvp(argv[0],argv);
This will always pass two arguments to ls. Even if pr1 and pr2 are empty, ls will still act like it was passed arguments. ls will determine how many arguments it has by looking for a NULL entry.
Your code has a flaw in that it is trying to hard code the number of arguments by splitting up the cmdArray into individual variables. This isn't going to work. For starters, commands take more than two arguments. You should instead leave cmdArray together, properly NULL terminate it, and pass that into execvp.

Hashtable words get overwritten in C

I am working with hashtables for the first time and I think I have a basic understanding of how they work. I am using a hashtable to check to see if a word exists in a file. The program takes in a "dictionary" file and a word check file. The program works fine when I have a small dictionary but when I use a very large one, the words get overwritten. I was hoping to get some insight as to why. Here is my code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <pthread.h>
#include <tgmath.h>
#include <ctype.h>
#include "hashtable_constants.h"
#define HASH_SIZE 500
#define MAX_WORD_SIZE 50
struct hashTable {
int collisions;
char** words;
};
struct hashTable hashTables[HASH_SIZE];
int hashKey(char * str)
{
int key = 0;
for(int j = 0; j <= 51; j++)
{
if(str[j] == '\0')
break;
key += (int)str[j];
}
key = key % HASH_SIZE;
return key;
}
int main(int argc, char** argv)
{
if(argc > 3)
{
fprintf(stderr, "Too many arguments!\n");
return -1;
}
else if(argc < 3)
{
fprintf(stderr, "Not enough arguments!\n");
return -1;
}
FILE *dictionary = fopen(argv[1], "r");
FILE *wordCheck = fopen(argv[2], "r");
if(dictionary == NULL || wordCheck == NULL ) //ensure input file exists
{
fprintf(stderr, "Error accessing input files\n");
return -1;
}
for(int i = 0; i < HASH_SIZE; i++)
{
hashTables[i].collisions = 0;
hashTables[i].words = malloc(HASH_SIZE * MAX_WORD_SIZE);
}
struct stat fileStat1;
struct stat fileStat2;
stat(argv[1], &fileStat1);
stat(argv[2], &fileStat2);
char* dictBuffer = (char*)malloc(fileStat1.st_size + 1);
char* wordCheckBuff = (char*)malloc(fileStat2.st_size + 1);
if (dictBuffer == NULL || wordCheckBuff == NULL)
{
fprintf (stderr, "Memory error");
return -1;
}
fread(dictBuffer, 1, (int)fileStat1.st_size, dictionary);
fread(wordCheckBuff, 1, (int)fileStat2.st_size, wordCheck);
char* word = malloc(MAX_WORD_SIZE + 1);
int count = 0;
for(int i = 0; i < (int)fileStat1.st_size; i++)
{
char c = dictBuffer[i];
if(isspace(c))
{
word[count] = '\0';
char* wordToAdd = word;
int key = hashKey(wordToAdd);
int collisionIndex = hashTables[key].collisions;
hashTables[key].words[collisionIndex] = wordToAdd;
hashTables[key].collisions++;
count = 0;
free(word);
word = malloc(MAX_WORD_SIZE + 1);
//printf("Added: %s to hashtable at key: %d\n",word,key);
}
else
{
word[count] = c;
count++;
}
}
count = 0;
for(int i = 0; i < (int)fileStat2.st_size; i++)
{
char c = wordCheckBuff[i];
if(isspace(c))
{
word[count] = '\0';
char* wordToCheck = word;
int key = hashKey(wordToCheck);
int collisionIndex = hashTables[key].collisions;
int foundWord = 0;
for(int j = 0; j < collisionIndex; j++)
{
if(hashTables[key].words[j] == wordToCheck)
{
printf("%s == %s\n",hashTables[key].words[j], wordToCheck);
foundWord = 1;
break;
}
}
if(foundWord == 0)
printf("Not a word: %s\n", wordToCheck);
/*else
printf("Key: %d -- Is a word: %s\n",key, word);*/
free(word);
word = malloc(MAX_WORD_SIZE + 1);
count = 0;
}
else
{
word[count] = c;
count++;
}
}
for(int i = 0; i < HASH_SIZE; i++)
free(hashTables[i].words);
free(word);
fclose(dictionary);
fclose(wordCheck);
printf("done\n");
return 0;
}
On problem is that in the line:
hashTables[key].words[collisionIndex] = wordToAdd;
You add 'wordToAdd' to the table.
But wordToAdd is equal to word. A few lines later you call
free(word);
So the hash table now holds a pointer to freed memory.
This will lead to all sorts of undefined behaviour in the program, quite possibly seg-faults too. Also it's very likely that since the memory is now 'free', a subsequent call to malloc might return this same pointer again - which you will then fill with another word. Hence you see the overwriting of strings.
You need to review how you use 'malloc' / 'free' generally in the program. If you want a pointer to refer to a valid string, you cannot call 'free' on that pointer during the intended lifetime of that string.
What you want to do is malloc each string, and add the pointers to the hashtable. Then when you've finished with the hashtable, and no longer need the string data, then call 'free' on all the pointers contained within it. In your case, this will probably need to be in your cleanup code at the end of your program's execution.

`Cannot find -lmalloc`, error: ld returned 1 exit status

Currently trying to compile this program using
g++ -o crack crack2.c -lcrypt -lpthread -lmalloc and am getting:
z#ubuntu:~/Desktop$ g++ -o crack crack2.c -lcrypt -lpthread -lmalloc
/usr/bin/ld: cannot find -lmalloc
collect2: error: ld returned 1 exit status
So.. If I remove the -lmalloc, I get undefined reference to 'passwordLooper(void*)'.
Really unsure of how to fix this problem. It has to be something related to malloc or -lmalloc because before I worked in the malloc(), everything worked as intended and the program compiled.
/*
crack.exe
*/
/* g++ -o crack crack.c -lcrypt -lpthread -lmalloc */
//define _GNU_SOURCE
#include <malloc.h>
#include <crypt.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
void *passwordLooper(void *passwordData);
//void *threadFunction(void *threads);
typedef struct{
int keysize;
char *target;
char *salt;
}passwordData;
int main(int argc, char *argv[]){ /* usage = crack threads keysize target */
int i = 0;
/* arg[0] = crack, arg[1] = #of threads arg[2] = size of password, arg[3] = hashed password being cracked */
if (argc != 4) {
fprintf(stderr, "Too few/many arguements give.\n");
fprintf(stderr, "Proper usage: ./crack threads keysize target\n");
exit(0);
}
int threads = *argv[1]-'0'; // threads is now equal to the second command line argument number
int keysize = *argv[2]-'0'; // keysize is now equal to the third command line argument number
char target[9];
strcpy(target, argv[3]);
char salt[10];
while ( i < 2 ){ //Takes first two characters of the hashed password and assigns them to the salt variable
salt[i] = target[i];
i++;
}
printf("threads = %d\n", threads); /*used for testing */
printf("keysize = %d\n", keysize);
printf("target = %s\n", target);
printf("salt = %s\n", salt);
if (threads < 1 || threads > 8){
fprintf(stderr, "0 < threads <= 8\n");
exit(0);
} /*Checks to be sure that threads and keysize are*/
if (keysize < 1 || keysize > 8){ /*of the correct size */
fprintf(stderr, "0 < keysize <= 8\n");
exit(0);
}
pthread_t t1,t2,t3,t4,t5,t6,t7,t8;
struct crypt_data data;
data.initialized = 0;
//~ passwordData.keysize = keysize;
//~ passwordData.target = target;
//~ passwordData.salt = salt;
passwordData *pwd = (passwordData *) malloc(sizeof(pwd));
pwd->keysize = keysize;
pwd->target = target;
pwd->salt = salt;
//~ if ( threads = 1 ){
//~ pthread_create(&t1, NULL, *threadFunction, threads);
//~ }
char unSalted[30];
int j = 0;
for (i = 2; target[i] != '\0'; i++){ /*generates variable from target that does not include salt*/
unSalted[j] = target[i];
j++;
}
printf("unSalted = %s\n", unSalted); //unSalted is the variable target without the first two characters (the salt)
char password[9] = {0};
passwordLooper(pwd);
}
/*_____________________________________________________________________________________________________________*/
/*_____________________________________________________________________________________________________________*/
void *passwordLooper(passwordData *pwd){
char password[9] = {0};
int result;
int ks = pwd->keysize;
char *target = pwd->target;
char *s = pwd->salt;
for (;;){
int level = 0;
while (level < ks && strcmp( crypt(password, s), target ) != 0) {
if (password[level] == 0){
password[level] = 'a';
break;
}
if (password[level] >= 'a' && password[level] < 'z'){
password[level]++;
break;
}
if (password[level] == 'z'){
password[level] = 'a';
level++;
}
}
char *cryptPW = crypt(password, s);
result = strcmp(cryptPW, target);
if (result == 0){ //if result is zero, cryptPW and target are the same
printf("result = %d\n", result);
printf ("Password found: %s\n", password);
printf("Hashed version of password is %s\n", cryptPW);
break;
}
if (level >= ks){ //if level ends up bigger than the keysize, break, no longer checking for passwords
printf("Password not found\n");
break;
}
}
exit(0);
}
Your code appears to be pure C. You should compile it with gcc, not g++.
The malloc function is declared in <stdlib.h> and implemented in the standard C library. You don't need either #include <malloc.h> or -lmalloc.
You have two inconsistent declarations for your passwordLooper function. Your "forward declaration":
void *passwordLooper(void *passwordData);
doesn't match the definition:
void *passwordLooper(passwordData *pwd){
/* ... */
}
The "forward declaration" of passwordLooper needs to follow the definition of the type passwordData.
You have this line:
//define _GNU_SOURCE
You need to uncomment it:
#define _GNU_SOURCE
to make the type struct crypt_data visible.
When I make all these changes, I'm able to compile it (at least on my system) with:
gcc c.c -o c -lcrypt

Resources