have to write a program displaying list of all logged users (their id and groups if -i or -g is used) using shared library. The functions in shared library are working correctly, but it seems like function pointer causes segmentation fault. Since it's a school assigment I have to use C and functions have to return nothing, and take only user name. I'm quite new to programming in linux (obviously).
main code:
#include <unistd.h>
#include <stdlib.h>
#include <utmp.h>
#include <dlfcn.h>
struct utmp *p;
int main(int argc, char* argv[]){
int opt, iflag = 0;
int gflag = 0;
void *handle;
while((opt = getopt(argc, argv, "ig")) != -1)
{
switch(opt)
{
case 'i':
iflag = 1;
break;
case 'g':
gflag = 1;
break;
default:
fprintf(stderr, "Błąd \n");
exit(EXIT_FAILURE);
}
}
handle = dlopen("./zad2lib.so", RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "Unable to open library: %s\n", dlerror());
iflag = 0;
gflag = 0;
}
while ((p = getutent()) != NULL) {
if (p->ut_type == USER_PROCESS)
{
if (iflag == 1) {
dlerror();
void (*func)(char*) = (void(*)())dlsym(handle, "userID");
func(p->ut_user);
}
printf("%s ", p->ut_user);
if (gflag == 1) {
dlerror();
void (*func)(char*) = (void(*)())dlsym(handle, "userGroups");
func(p->ut_user);
}
}
printf("\n");
}
dlclose(handle);
}
return 0;
}
.so file:
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
void userID(char *name) {
struct passwd *pw = getpwnam(name);
printf("%d ", pw->pw_uid);
}
void userGroups(char *name) {
struct passwd *pw = getpwnam(name);
int i;
int gidsize = 100;
struct group* g;
gid_t *grouplist = malloc(gidsize*sizeof(gid_t));
getgrouplist(name, pw->pw_gid, grouplist, &gidsize);
printf("[");
for (i = 0; i < gidsize; i++) {
g = getgrgid(grouplist[i]);
printf(" %s", g->gr_name);
}
printf(" ]");
free(grouplist);
}
Related
I have problems with my code. It's a multithreading program that executes the following Linux command "# cat | sort | uniq -c | sort -nr". When I try to run the program in a virtual machine, I get a segmentation error, no core dumped. I have tried everything to fix this, but I still get the error. I see that the problem is in the main function and I don't know what it is. Could be either in pthread_join or maybe could be the max number of threads, declared globally. Can someone help me out? This is my code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define MAX_THREADS 0x40
#define MAX_STRING 124ULL
struct string_count_entry {
char* string;
int count;
};
struct string_count {
int nb_string;
struct string_count_entry* entries;
};
struct string_count* string_count_init() {
struct string_count* sc;
sc = malloc(sizeof(sc));
sc->entries = NULL;
sc->nb_string = 0;
return sc;
}
int addstring(struct string_count* pt, char* s) {
int i;
for (i = 0; i < pt->nb_string; i++) {
if (strcmp(pt->entries[i].string, s))
break;
}
if (i == pt->nb_string) {
pt->entries = realloc(pt->entries,
pt->nb_string + 1 * sizeof(pt->entries[0]));
if (pt->entries == NULL)
return -1;
pt->nb_string++;
pt->entries[i].string = s;
}
pt->entries[i].count++;
return 0;
}
static inline int Compare(const void* pt1, const void* pt2) {
struct string_count_entry* a = malloc(sizeof(pt2));
struct string_count_entry* b = malloc(sizeof(pt1));
if (a->count == b->count)
return strcmp(a->string, b->string);
return a->count - b->count;
}
void string_count_pint(struct string_count* sc) {
int i;
qsort(sc->entries, sc->nb_string, sizeof(struct string_count), Compare);
i = 0;
while (i < sc->nb_string) {
printf("%d %s\n", sc->entries[i].count, sc->entries[i].string);
i++;
}
}
void string_count_free(void* pt) {
struct string_count* sc = malloc(sizeof(pt));
char i;
for (i = 0; i < sc->nb_string; i++) {
free(sc->entries[i].string);
}
free(sc->entries);
}
char* readline(void) {
int i = 0;
char c;
char* linebuf = (char*)malloc(MAX_STRING);
while (read(0, &c, 1) != 0) {
if (c == '\n') {
linebuf[i] = '\0';
return linebuf;
}
linebuf[i++] = c;
}
return NULL;
}
void* thread_main(void* arg) {
struct string_count* sc = malloc(sizeof(arg));
char* line;
while ((line == readline()) != '\0') {
addstring(sc, line);
}
return NULL;
}
int main(int argc, char** argv) {
int nbthreads;
int i;
pthread_t threads[MAX_THREADS];
struct string_count* sc;
if (argc != 1) {
fprintf(stderr, "usage: %s <nb threads>\n", argv[0]);
return EXIT_FAILURE;
}
nbthreads = atoi(argv[1]);
sc = malloc(sizeof(nbthreads));
for (i = 0; i < nbthreads; i++) {
pthread_create(&threads[i], NULL, thread_main, sc);
}
do {
pthread_join(threads[nbthreads--], NULL);
} while (nbthreads > 0);
string_count_free(sc);
string_count_pint(sc);
return EXIT_SUCCESS;
}
I suspect the bug is in this line: sc = malloc(sizeof(nbthreads));
You probably wanted sc = malloc(sizeof(string_count));
I'm also not sure if struct string_count* sc = malloc(sizeof(arg)); does what you intended in thread_main.
You probably need the sc in main be an array and pass a different item in it to each thread and then aggregate them after the join.
Here are the first few errors I have spotted, in no particular order.
Unprotected modification of data structures from multiple threads. Read something about multithreading. Pay attention to the word "mutex".
pthread_join(threads[nbthreads--], NULL); goes out of bounds.
struct string_count* sc = malloc(sizeof(arg)); makes no sense. sizeof(arg) is the size of a pointer (8 on most PC-like systems). This is not enough to hold one struct string_count.
struct string_count_entry* a = malloc(sizeof(pt2)); apparently has even less sense. You are allocating something in a string comparison function, using a wrong size, then you are using the allocated memory without initializing it, and without even trying to compare the things passed to the function.
while ((line == readline()) != '\0') does not assign anything.
pt->entries = realloc(pt->entries, pt->nb_string + 1 * sizeof(pt->entries[0])); is missing a couple of parentheses.
I am creating a struct called Job and I want to create an array of struct Job. The name of my array is jobQueue I populate the array using commandline args. The instructor has it set up to where **args is being used. After the user inputs the name of the job and the execution time it gets added to the array. However, when I try to print jobQueue[0].name using the list() funct I have written, the name does not get printed. I'm trying to get my code set up to where I can print the name. I have provided a minimal version of my overall project that just focuses on the specific problem I am encountering and should compile and run fine.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/wait.h>
#include <stdint.h>
#define EINVAL 1
#define E2BIG 2
#define MAXMENUARGS 7
//structure job initialize
struct Job {
//initializing name variable
char *name;
int executionTime;
};
//init the array
struct Job jobQueue[5] = {0};
//cmd function provided by intructor
int cmd_run(int nargs, char **args) {
int execT;
sscanf(args[2], "%d", &execT);
run(args[1], execT);
return 0;
}
//cmd function provided by intructor
void cmd_list() {
list();
}
//cmd function provided by intructor
static struct {
const char *name;
int (*func)(int nargs, char **args);
} cmdtable[] = {
/* commands: single command must end with \n */
{ "r", cmd_run},
{ "run", cmd_run},
{ "list\n", cmd_list}
};
//cmd function provided by intructor
//this is the function that handles the arguments entered by the user
//provided it just in case someone needs to see how arguments are being
//processed
int cmd_dispatch(char *cmd) {
time_t beforesecs, aftersecs, secs;
u_int32_t beforensecs, afternsecs, nsecs;
char *args[MAXMENUARGS];
int nargs = 0;
char *word;
char *context;
int i, result;
void *Dispatcher(void *arg);
for (word = strtok_r(cmd, " ", &context);
word != NULL;
word = strtok_r(NULL, " ", &context)) {
if (nargs >= MAXMENUARGS) {
printf("Command line has too many words\n");
return E2BIG;
}
args[nargs++] = word;
}
if (nargs == 0) {
return 0;
}
for (i = 0; cmdtable[i].name; i++) {
if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) {
assert(cmdtable[i].func != NULL);
/* Call function through the cmd_table */
result = cmdtable[i].func(nargs, args);
return result;
}
}
printf("%s: Command not found\n", args[0]);
return EINVAL;
}
//adds job to the array using user arguments
void run(char name[], int executionTime) {
//creates a job using the arguments specified by user
struct Job job = {name, executionTime};
jobQueue[0] = job;
printf("\nJob added to queue now please type 'list'\n");
}
//name will not print here
void list() {
printf("\nSee how the name will not print below?\n");
char executionTimeStr[5];
for (int c = 0; c < sizeof (jobQueue) / sizeof (jobQueue[0]); c++) {
//prints job info formatted
if (jobQueue[c].name != NULL) {
sprintf(executionTimeStr, "%d", jobQueue[c].executionTime);
//job name will not print here, output is just left blank
printf("%s %20.8s", "Name", "ExecTime");
printf("%-10.15s %11.3s\n",
jobQueue[c].name,
executionTimeStr
);
}
}
}
int main(int argc, char *argv[]) {
printf("Welcome to our batch job scheduler\n");
printf("Please enter the following exactly: 'run job1 10' \n");
//ignore this, it handles my commandline parser
char *buffer;
size_t bufsize = 64;
buffer = (char*) malloc(bufsize * sizeof (char));
if (buffer == NULL) {
perror("Unable to malloc buffer");
exit(1);
}
while (1) {
printf("User Input: ");
getline(&buffer, &bufsize, stdin);
cmd_dispatch(buffer);
}
//ignore this, it handles my commandline parser
return 0;
}
This function is a part of program which will gain statistics about books (amount of specific letters, words etc.). Thing is that segmentation fault appears when trying to malloc:
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
after reallocing whole array
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
I know that realloc isn't really efficent but the most important thing at the moment is to understand why it doesn't work at all. Thanks a lot.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <wctype.h>
#include <wchar.h>
#define X 2
void wordManager(wchar_t ***, int **, wchar_t *);
int main(int argc, char **argv){
setlocale(LC_ALL, "");
wchar_t **wordArray;
int *wordAmount;
wchar_t word[50];
for(int i=0; i<X; i++){
scanf("%ls", word);
wordManager(&wordArray, &wordAmount, word);
}
for(int i=0; i<X; i++){
printf("%ls; %d times\n", wordArray[i], wordAmount[i]);
}
}
void wordManager(wchar_t ***wordArray, int **wordAmount, wchar_t *newWord){
static int isArrayInitialised = 0;
static int isArrayEmpty = 1;
static int arrayIndex = 0;
int wordLocation;
if(!isArrayInitialised){
*wordArray = malloc(sizeof(**wordArray)*1);
if(*wordArray==NULL){
printf("Error mallocing wordArray");
exit(EXIT_FAILURE);
}
*wordAmount = calloc(1, sizeof(*wordAmount));
if(*wordAmount==NULL){
printf("Error callocing wordAmount");
exit(EXIT_FAILURE);
}
isArrayInitialised = 1;
}
if(isArrayEmpty){
*wordArray[0] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[0], newWord);
*wordAmount[0] = 1;
isArrayEmpty = 0;
}
else{
//Check if word is already in an array.
wordLocation = 0;
for(; wordLocation<arrayIndex+1; wordLocation++){
if(!wcscmp(*wordArray[wordLocation], newWord)) break;
}
printf("%d\n", wordLocation);
//Word hasn't been found. Then:
if(wordLocation==arrayIndex+1){
arrayIndex++; //Increase arrays' volume.
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
if(*wordArray==NULL){
printf("Error reallocating wordArray memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordAmount = realloc(*wordAmount, (arrayIndex+1)*sizeof(**wordAmount));
if(*wordAmount==NULL){
printf("Error reallocating wordAmount memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[arrayIndex], newWord);
*wordAmount[arrayIndex] = 1;
}
//Word has been found in an array.
else{
(*wordAmount[wordLocation])++;
}
}
}
I have this four files,
tinyll.c tinyll.h in /home/user/lib
test.c tinyll.h in /home/user/code
and compile with this instructions for create a static library
libtinyll.a and use it.
; in lib
$ gcc -c tinyll.c
$ ar -cvq libtinyll.a *.o
; in code
$ gcc -o test test.c ../lib/libtinyll.a
Until here all is ok. But I don't know why I obtain segmentation fault because the lines from [CODE ERROR] but showElements work. The target is not pass code from test.c to tinyll.c for treat the tiny list linked. How fix that?
/////////////////////////////////// test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
int main(int argc, char *argv[])
{
progname = argv[0];
char *file = "fwords";
int n;
PTLL lsone = NULL;
n = loadfileinTLL(file,&lsone);
// work. good.
showElements(lsone);
// [CODE ERROR]
// Why here dont work?
// segmentation fault, load the first word
// but in the second crash.
while (lsone != NULL) {
printf("%s",lsone->word);
lsone = lsone->next;
}
return 0;
}
/////////////////////////////////// tinyll.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
void addElement(PPTLL lst, char data[])
{
PTLL elemt;
elemt = (PTLL) malloc(sizeof(TLL));
if (elemt == NULL) {
fprintf(stderr, "%s: insufficient memory.\n", progname);
exit(1);
}
if (*lst == NULL)
{
strncpy(elemt->word, data, 45);
elemt->next = NULL;
*lst = elemt;
}
else {
// add in front of list
strncpy(elemt->word, data, 45);
elemt->next = *lst;
*lst = elemt;
}
}
void showElements(PTLL lst)
{
while (lst != NULL) {
printf("%s\n",lst->word);
lst = lst->next;
}
}
int loadfileinTLL(char *filepath, PPTLL plst)
{
FILE *f;
if ((f = fopen(filepath, "r")) == NULL) {
fprintf(stderr, "%s: error to load file %s.\n", progname, filepath);
exit(1);
}
char buf[45]; int n=0;
while (fgets(buf,sizeof(buf),f) != NULL) {
char *nl;
if ((nl = strchr(buf,'\n')) != NULL) {
*nl = '\0';
}
addElement(plst,buf);
n++;
}
fclose(f);
return n;
}
//////////////////////////////////// tinyll.h
#include <stdio.h>
#include <stdlib.h>
#ifndef _TINYLL_
#define _TINYLL_
struct list {
char word[45];
struct list *next;
};
// Tiny Linked List
typedef struct list TLL;
typedef struct list *PTLL;
typedef struct list **PPTLL;
char *progname;
#endif
the following code:
1) compiles cleanly
2) performs correctly, with out seg faulting.
3) checks and handles errors correctly
4) cleans up after itself, by freeing any allocated memory
5) removed leading underscores from names
as leading underscores has special meaning to the compiler
tinyll.h
#ifndef TINYLL_
#define TINYLL_
struct list
{
char word[45];
struct list *next;
};
// Tiny Linked List
typedef struct list TLL;
typedef struct list *PTLL;
typedef struct list **PPTLL;
extern char *progname;
void addElement(PPTLL lst, char data[]);
void showElements(PTLL lst);
int loadfileinTLL(char *filepath, PPTLL plst);
#endif // TINYLL_
tinyll.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
void addElement(PPTLL lst, char data[])
{
PTLL elemt;
elemt = (PTLL) malloc(sizeof(TLL));
if (elemt == NULL) {
fprintf(stderr, "%s: insufficient memory.\n", progname);
exit(1);
}
if (*lst == NULL)
{
strncpy(elemt->word, data, 45);
elemt->next = NULL;
*lst = elemt;
}
else {
// add in front of list
strncpy(elemt->word, data, 45);
elemt->next = *lst;
*lst = elemt;
}
}
void showElements(PTLL lst)
{
while (lst != NULL) {
printf("%s\n",lst->word);
lst = lst->next;
}
}
int loadfileinTLL(char *filepath, PPTLL plst)
{
int n=0;
FILE *f;
if ((f = fopen(filepath, "r")) == NULL)
{
fprintf(stderr, "%s: error to load file %s.\n", progname, filepath);
n = -1;
}
else
{
char buf[45];
while (fgets(buf,sizeof(buf),f) != NULL)
{
char *nl;
if ((nl = strchr(buf,'\n')) != NULL)
{
*nl = '\0';
}
addElement(plst,buf);
n++;
}
fclose(f);
} // endif
return n;
}
test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
char *progname;
int main(int argc, char *argv[])
{
if( 1 == argc )
{
progname = argv[0];
}
else
{
printf( "USAGE: %s\n", argv[0]);
exit( EXIT_FAILURE );
}
// implied else, right number (0) of arguments on command line
char *file = "fwords";
int n;
PTLL lsone = NULL;
PTLL lstwo = NULL;
n = loadfileinTLL(file,&lsone);
if( n > 0 )
{
// work. good.
showElements(lsone);
// [CODE ERROR]
// Why here dont work?
// segmentation fault, load the first word
// but in the second crash.
lstwo = lsone;
while (lstwo)
{
printf("%s",lstwo->word);
lstwo = lstwo->next;
}
} // endif
while( lsone )
{
lstwo = lsone->next;
free(lsone);
lsone = lstwo;
} // end while
return 0;
}
I used the following for a test file:
one
two
three
four
five
six
and the output was:
six
five
four
three
two
one
sixfivefourthreetwoone
Can anyone give me some indication as to why array of structs doesn't print out properly ?
I think its something to do with the memory I have allocated to the struct I am unsure !!
Using mac osx mountain lion xcode 4 gcc
Thanks for any help completely stuck!!
(Please have patience I am only a student !)
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct{
char* one;
char* two;
} Node;
Node *nodes;
int count = 0;
//-----------------------------------------------------------------------
void add(char *one,char*two){
char x[40];
char y[40];
printf("reached..\n");
strcpy(x,one);
strcpy(y,two);
printf("--> X: %s\n",x);
printf("--> Y: %s\n",y);
Node newNode;
newNode.one = x;
newNode.two = y;
nodes[count]= newNode;
count++;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void print(){
int x;
for (x = 0; x < 10; x++)
{
printf("%d : (%s, %s) \n",x,nodes[x].one, nodes[x].two);
}
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void check(char **arg)
{
if(strcmp(*arg, "Add") == 0)
{
add(arg[1],arg[2]);
}else if(strcmp(*arg,"print") == 0)
{
print();
}else{
printf("Error syntax Enter either: \n Add [item1][item2]\n OR \n print\n");
}
}
//-----------------------------------------------------------------------
void readandParseInput(char *line,char **arg)
{
if (fgets (line, 512, stdin)!= NULL) {
char * pch;
pch = strtok (line," \n\t");
int count = 0;
arg[0] = pch;
while (pch != NULL)
{
count++;
pch = strtok (NULL, " \n\t");
arg[count] =pch;
}
}else{
printf("\n");
exit(0);
}
}
//-----------------------------------------------------------------------
int main()
{
int size = 100;
nodes = calloc(size, sizeof(Node));
int i;
for(i = 0;i <100; i++){
printf("%s , %s \n",nodes[i].one,nodes[i].two );
// nodes[i].one = ".";
// nodes[i].two = ".";
}
char line[512]; /* the input line */
char *arg[50]; /* the command line argument */
while (1)
{
readandParseInput(line,arg);
if(arg[0] != NULL){
check(arg);
}
}
return(0);
}
You're keeping pointers to the following automatic variables:
char x[40];
char y[40];
These go out of scope when add() returns, leaving you with dangling pointers.
You either have to turn Node::one and Node::two into arrays, or allocate memory for them on the heap.
In you add() function, you cannot assign one struct to another via an = operator... you would have to copy it...
memcpy( &nodes[count], &newNode )
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *fn;
}NAME;
#define NAME_LEN 20
int main()
{
NAME name;
name.fn = (char *) calloc(NAME_LEN, sizeof(char));
strcpy(name.fn, "Namco");
printf("Name: %s\n", name.fn);
free(name.fn);
return 0;
}
you can't just assign a string like this in c
newNode.one = x;
newNode.two = y;
what is newNode.one referring to???
at Function add
newNode.one = x;
newNode.two = y;
to
newNode.one = strdup(x);
newNode.two = strdup(y);