getgrnam() causing error for no apparent reason? - c

I am getting an error that makes no sense. I have the following code -
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <grp.h>
gid_t groupIdFromName(const char *name)
{
struct group *grp;
gid_t g;
char *endptr;
if (name == NULL || *name == '\0')
return -1;
g = strtol(name, &endptr, 10);
if (*endptr == '\0')
return g;
grp = getgrnam(name);
if (grp == NULL)
return -1;
return grp->gr_gid;
}
int main(int argc, char** argv) {
return (EXIT_SUCCESS);
}
I am using NetBeans in Linux Mint and when I try and while my program builds without problems, when I try and run it I get the following error -
Signal received: SIGSEGV (?) with sigcode ? (?)
From process: ?
If I comment out the line grp = getgrnam(name); this error goes away. But I don't understand why this line should cause it to fail, particularly since my main method is blank.

I have found that many people have been experiencing this bug for quite some time in NetBeans and Code::Blocks. I tried the code in Eclipse and it works fine. So don't use NetBeans for C development on Linux is my advice.

Related

How to solve address boundary error when adding to `dict` of Redis?

I want to do some basic put/get tests based on dict. But when doing dictAdd, error was thrown.
Code
// dict_test.c
#include <stdio.h>
#include "dict.h"
int main(int argc, char *argv[]) {
// create
dictType hashDictType;
dict *d = dictCreate(&hashDictType, NULL);
printf("Created: %s\n", d == NULL ? "Failed" : "OK");
// put
char key[] = "hello";
char value[] = "world";
dictAdd(d, key, value);
return 0;
}
Error message
'./dict_test' terminated by signal SIGSEGV (Address boundary error)
GCC version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Compile command
gcc dict_test.c dict.c zmalloc.c siphash.c -o dict_test
I found the error thrown when executing dictIsRehashing(d) which is a macro(#define dictIsRehashing(d) ((d)->rehashidx != -1)).
So I've tried print d->rehashidx directly. But i still got the same error.
printf("%ld \n", d->rehashidx);
printf("%s", ((d)->rehashidx) == -1L ? "False" : "True");
The output
Created: OK
-1
fish: './dict_test' terminated by signal SIGSEGV (Address boundary error)
Maybe this is a basic c problem. Any hints will be appreciated.
Steps to reproduce
I download the source code of Redis :).
Paste the demo code under directory src.
Solution by OP.
The problem is when using dict a hash function is required to be init on your own which I thought it have a default one. By define a hash function, the crash problem solved.
#include <stdio.h>
#include <strings.h>
#include "dict.h"
// a hash function defined
uint64_t dictSdsCaseHash(const void *key) {
// refer to "siphash.c"
return dictGenCaseHashFunction((unsigned char*)key, (int) strlen((char*)key));
}
int main(int argc, char *argv[]) {
// create
dictType hashDictType;
hashDictType.hashFunction = dictSdsCaseHash;
dict *d = dictCreate(&hashDictType, NULL);
printf("Created: %s\n", d == NULL ? "Failed" : "OK");
// put
char key[] = "hello";
char value[] = "world";
dictAdd(d, key, value);
// get
dictEntry *entry = dictFind(d, key);
printf("Value: %s\n", entry->v);
return 0;
}
Output
Created: OK
hello
Value: world

Auto-completion visual not good (readline.h)

I would like to add the auto completion on the shell I created. I could not put the entire code but I can tell you my shell is working!
So I tried to implement auto-completion by using the readline function but the result is not that great (see the code in commentary I tried): the auto-completion works but the problems are:
1. I need to press twice enter to get the command executed now. 2. I need to type twice the command (like "ls") to get it executed! Can you help me to fix this? thank you :)
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <stdio.h>
#include "includes/ft_sh1.h"
int main(int ac, char **av, char **envp)
{
char *line;
t_env *e = NULL;
char *add;
if (!(e = (t_env *)malloc(sizeof(t_env))))
return (0);
e->envp = env_cpy(envp, 0, 0);
init_env(e);
while (1)
{
--> My question is only about this part below <--
ft_printf("shell$> ");
// add = readline( "shell ");
// add_history(add);
// printf("%s", add);
--> My question is only about this part above <--
get_next_line(0, &line);
get_pwd_env(e);
e->cmd = get_cmd(e, line);
if (ft_strcmp(line, "exit") == 0)
exit(0);
else if (ft_strncmp(e->cmd[0], "cd", 2) == 0)
cd_cmd(e);
else
ft_execute(av, line, e);
}
}
When you just uncomment the part of code in question, you still have the call
get_next_line(0, &line);
in your program, so no wonder that you need to type two command lines.

creating multiple recursive directories in c

I am completing cs50x (the edX (free) version of the Harvard cs50) course and am trying to be a bit tricky/lazy/test myself.
I am trying to use a C program to create all the directories I will need for my psets.
I have looked online and found that <sys/stat.h> includes the mkdir() function and therefore tried creating some nested loops to create all the necessary folders by doing something similar to mkdir {pset1,pset1/{standard,hacker},pset2,pset2{standard... to give me a directory structure like this:
pset1/Standard
pset1/Hacker
pset2/Standard
etc...
I came up with this:
#include <cs50.h>
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, string argv[])
{
for(int i = 1; i <=8; i++)
{
string dir = argv[1];
sprintf(dir,"%s%i", argv[1], i);
mkdir(dir, 0777);
for(int j = 0; j<2; j++)
{
string subDir[] = {"Standard","Hacker"};
sprintf(dir,"%s%i/%s", argv[1], i, subDir[j]);
mkdir(dir, 0777);
}
}
}
However, the program only creates pset1 and completes, there are no subfolders, no pset2 etc.
Yes, you're being lazy since you seem to have very little knowledge of C, yet try to program in it. :)
C is not Python, there is no string interpolation/formatting operator. You have to call a function, specificially snprintf(). Read that manual page.
Also, you can't create a bunch of nested directories with a single call to mkdir(). Read the manual page.
To create nested directories, you're either going to have to build each's absolute path (i.e. each successive time you call mkdir() the path will be longer than the previous time), or actually enter each directory as you create it, and go from there.
To create a full path you can call mkdir() recursivly like this:
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
int mkdirr(const char * path, const mode_t mode, const int fail_on_exist)
{
int result = 0;
char * dir = NULL;
do
{
if (NULL == path)
{
errno = EINVAL;
result = -1;
break;
}
if ((dir = strrchr(path, '/')))
{
*dir = '\0';
result = mkdirr(path, mode, fail_on_exist);
*dir = '/';
if (result)
{
break;
}
}
if (strlen(path))
{
if ((result = mkdir(path, mode)))
{
char s[PATH_MAX];
sprintf(s, "mkdir() failed for '%s'", path);
perror(s);
if ((EEXIST == result) && (0 == fail_on_exist))
{
result = 0;
}
else
{
break;
}
}
}
} while (0);
return result;
}
And then call mkdirr() like this;
int main(void)
{
char p[] = "test/1/2/3";
if (-1 == mkdirr(p, 0777, 0))
{
perror("mkdirr() failed()");
}
return 0;
}

My Program Keeps Failing With - Error While Loading Shared Libraries

I wrote a program "run_coffee.c" to implement fork() and exec() system calls. It fundamentally calls exec to start another process "coffee" built through "coffee.c" multiple times. The problem is I am running this program on cygwin64 in windows environment and it keeps failing with the following error -
**
error while loading shared libraries: ?: cannot open shared object
file: no such file or directory
**
I also ran cygcheck to see wether dependencies are being met or not. This is the output -
C:\cygwin64\home\Admin\run_coffee.exe C:\cygwin64\bin\cygwin1.dll
C:\Windows\system32\KERNEL32.dll
C:\Windows\system32\API-MS-Win-Core-RtlSupport-L1-1-0.dll
C:\Windows\system32\ntdll.dll C:\Windows\system32\KERNELBASE.dll
C:\Windows\system32\API-MS-Win-Core-ProcessThreads-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Heap-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Memory-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Handle-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Synch-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-File-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-IO-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-ThreadPool-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-LibraryLoader-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-NamedPipe-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Misc-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-SysInfo-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Localization-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-ProcessEnvironment-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-String-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Debug-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-ErrorHandling-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Fibers-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Util-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Profile-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Security-Base-L1-1-0.dll
No error or unmet dependency showed up so I guess all dependencies are being met. So what is causing this problem? Please Help.
Here are the two programs -
coffee.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
char *w = getenv("EXTRA");
if (!w)
w = getenv("FOOD");
if (!w)
w = argv[argc-1];
char *c = getenv("EXTRA");
if (!c)
c = argv[argc-1];
printf("%s with %s\n", c, w);
return 0;
}
run_coffee.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
struct food_options
{
char *food;
char *extra;
};
int main()
{
int i;
char **env;
env[0] = (char*)malloc(sizeof(char) * 20);
env[1] = (char*)malloc(sizeof(char) * 20);
env[2] = (char*)malloc(sizeof(char) * 20);
struct food_options *opts = (struct food_options *)malloc(sizeof(struct food_options) * 3);
opts[0].food = "coffee";
opts[0].extra = "donuts";
opts[1].food = "fish";
opts[1].extra = "chips";
opts[2].food = "kabab";
opts[2].extra = "parantha";
for (i = 0; i < 3; i++)
{
pid_t pid = fork();
if (pid == -1)
{
fprintf(stderr, "Cannot fork process. Fatal Error %s\n", strerror(errno));
return 1;
}
else if (!pid)
{
sprintf(env[0], "FOOD=%s", opts[0].food);
sprintf(env[1], "EXTRA=%s", opts[0].extra);
env[2] = NULL;
if (execle("coffee.exe","coffee.exe",NULL,env) == -1)
{
fprintf(stderr, "Cannot execute coffee.exe. Error %s\n", strerror(errno));
}
}
}
free(opts);
free(env[0]);
free(env[1]);
free(env[2]);
return 0;
}
There is a memory bug in your program which can cause undefined behavior: you declared env to be an array of char*'s, but you did not initialize env. Hence, env[0], env[1], and env[2] point to random locations in memory. When you do sprintf(env[0], ...) and sprintf(env[1], ...), you are writing data to some random location in memory (where ever env[0] and env[1] points to). This can cause almost anything to happen, including modification of the names of libraries, making you unable to load them.

How to use fgetpwent()?

I am trying to get a list of all the users in the system (linux, fedora).
and i've heard that the function:fgetpwent is the one that i need to that mission.
the sad part is that i didnt find any documentation or example of how to use this function.
if someone would give me an example, that would be great, thanks in advance.
No idea why I ever could have used it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <crypt.h>
#include <pwd.h>
#include <sys/types.h>
char *testentry = "testread";
static void read_etc_passwd (void) {
struct passwd *pwd_entry = NULL;
int found = 0;
setpwent(); // go to the top of /etc/passwd
while (!found && (pwd_entry = getpwent())){
if (0 == strcmp (testentry, pwd_entry->pw_name)){
found = 1;
}
}
if (found) {
printf ("name = %s\nhome = %s\n", pwd_entry->pw_name,
pwd_entry->pw_dir);
} else {
puts("could not find the entry you were looking for, or"
"some error occurred");
}
}
void change_etc_passwd (void){
struct passwd *pwd = NULL;
FILE *pwd_fd = NULL;
FILE *pwd_new = NULL;
int result = 0;
pwd_fd = fopen ("/etc/passwd", "r");
pwd_new = fopen ("/tmp/passwd.neu", "a");
// assuming everthing went fine (bad idea)
while (pwd = fgetpwent (pwd_fd)){
if (0 == strcmp (pwd->pw_name, testentry)){
pwd->pw_passwd = crypt ("new_pwd", "aa");
}
result = putpwent(pwd, pwd_new);
if (result < 0){
fprintf (stderr, "Failed to write entry, giving up\n");
exit (EXIT_FAILURE);
}
}
}
int main (void) {
/* handling of /etc/passwd */
read_etc_passwd ();
change_etc_passwd();
return 0;
}
Add error handling and it may even work without breaking ;-)

Resources