I tried to get the return value in the signal handler function, using the longjmp(), but the program return which is not what I expected. Can someone help me? The code is as follows:
void SignalHandler(int sig)
{
longjmp(frameInfo, -2);
}
int main(int argc, char** argv)
{
signal(SIGSEGV, SignalHandler);
if(setjmp(frameInfo) == 0) {
void* ptr = NULL;
int a = *((int *)ptr);
printf("%d\n", a);
return -1;
} else {
printf("in \n"); // printf can work
exit(-2); // or return -2;
}
return 1;
}
I don't know what happened after the printf.
update:
By check assemble code, I see the expected return value.
mov $0xfffffffe,%eax
Compile code and generate a.out, use python or shell check return, ret = 254:
// python
cmd = ./a.out
a = subprocess.Popen(cmd, shell = True)
ret = a.wait()
// shell
./a.out
echo $?
My guess is that after the program returned, the operating system did something special. The question is how do I get the real return value?
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
char** get_env(void){
char *ptr, *ch, *next_ptr;
char **tok = malloc(sizeof(char*) * 20);
int i = 0;
ch = getenv("PATH");
for(i=0, ptr=ch; ;ptr=NULL,i++){
tok[i] = strtok_r(ptr, ":", &next_ptr);
if(tok[i] == NULL) break;
}
tok[i] = NULL;
return tok;
}
char **get_input(char *input){
char **command = malloc(8 * sizeof(char *));
char *separator = " ";
char *parsed, *nextptr;
int index = 0;
parsed = strtok_r(input, separator, &nextptr);
while(parsed != NULL){
command[index] = parsed;
index++;
parsed = strtok_r(NULL, separator, &nextptr);
}
command[index] = NULL;
return command;
}
int main(void) {
char **env = get_env();
pid_t pid;
int stat_loc;
while(1) {
int i = 0;
char *nextptr, *parsed;
char *command[20];
char* input = malloc(sizeof(char)*20);
printf("$>");
input = fgets(input,19,stdin);
input[strlen(input) - 1] = '\0';
if(strcmp("exit",input) == 0) {
free(input);
break;
}
parsed = strtok_r(input, " ",&nextptr);
while(parsed) {
command[i] = parsed;
printf("%s \n", command[i]);
i++;
parsed = strtok_r(NULL, " ", &nextptr);
}
command[i] = NULL;
pid = fork();
if(pid == 0){
if(execvp(command[0], command) == -1) {
printf("FAILED \n");
exit(0);
}
}
if(pid > 0){
wait(&stat_loc);
}
free(input);
}
free(env);
return 0;
}
I am trying to write a simple linux shell program in C. execvp function is being used.
when command[0](char *) and command(char * []) is entered to execvp, return value is only -1, it doesn't show running program such as pwd, ls.
I searched several blogs and manuals in web, but i can't find how to solve this error.
How can i make execvp function work?
---edited---
when i input ls -a in char* input variable, strtok_r function devide the string to pointer array(char * command[]), and command(command[0]) and argument(command) is entered execvp function.
i want to execute appropriate program such as cd, pwd, ls. But i cannot see program running, "FAILED" is only shown.
I have this uboot
VERSION = 2017
PATCHLEVEL = 03
I am trying to silent the console using the silent variable.I defined this #define CONFIG_SILENT_CONSOLE
So at boot time I am interrupting the console, and entering
setenv silent 1
save
reset
Now after reset, or power on reset I try again get console logs.After seeing env variables
printenv
I see my saved variable correctly in env varibles
silent=1
but still u-boot is not silent. I suspect this function is failing at checking for this env variable,
char *getenv(const char *name)
{
if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
ENTRY e, *ep;
WATCHDOG_RESET();
e.key = name;
e.data = NULL;
hsearch_r(e, FIND, &ep, &env_htab, 0); /*this function is maybe returning*/
return ep ? ep->data : NULL;
}
/* restricted capabilities before import */
if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
return (char *)(gd->env_buf);
return NULL;
}
But what exactly is happening?
Is there something like before relocation time env variables and after relocation env variables because the function,
static void console_update_silent(void)
{
#ifdef CONFIG_SILENT_CONSOLE
if (getenv("silent") != NULL){
puts("silent");
gd->flags |= GD_FLG_SILENT;
}
else{
puts("Non silent");
gd->flags &= ~GD_FLG_SILENT;
}
#endif
}
/* Called before relocation - use serial functions */
int console_init_f(void)
{
gd->have_console = 1;
console_update_silent();
print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
return 0;
}
console_init_f says its before relocation.
I have put some prints to see and always gets non silent, even if I have saved the silent variable,
I am using a sd card to boot(mmc), I don't have any debugger, so I
I tried printing default environment, as
env print default
## Error: "default" not defined
So there is not default environment too.
Any tips or help will make me understand.
P.S.
I explicitly defined silent in #define CONFIG_EXTRA_ENV_SETTINGS
Now u-boot is silent.
Doing a setenv silent should remove this from env variable, and I can see that its gone, but still on reboot my uboot is silent.
So something about environment variable is clearly mystery to me.
P.P.S
I come to see this code,
int getenv_f(const char *name, char *buf, unsigned len)
{
int i, nxt;
for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
int val, n;
for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) {
if (nxt >= CONFIG_ENV_SIZE)
return -1;
}
val = envmatch((uchar *)name, i);
if (val < 0)
continue;
/* found; copy out */
for (n = 0; n < len; ++n, ++buf) {
*buf = env_get_char(val++);
if (*buf == '\0')
return n;
}
if (n)
*--buf = '\0';
printf("env_buf [%d bytes] too small for value of \"%s\"\n",
len, name);
return n;
}
return -1;
}
Which is called by this
char *getenv(const char *name)
{
if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
ENTRY e, *ep;
WATCHDOG_RESET();
e.key = name;
e.data = NULL;
hsearch_r(e, FIND, &ep, &env_htab, 0);
return ep ? ep->data : NULL;
}
/* restricted capabilities before import */
if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
return (char *)(gd->env_buf);
return NULL;
}
From early board_init_f
this function
int env_init(void)
{
/* use default */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
return 0;
}
makes env_addr to point always to read only memory of the code, and does not point to anything else such as where mmc environment are saved.
So this function always point to default_environment variable.
__weak uchar env_get_char_spec(int index)
{
return *((uchar *)(gd->env_addr + index));
}
static uchar env_get_char_init(int index)
{
/* if crc was bad, use the default environment */
if (gd->env_valid)
return env_get_char_spec(index);
else
return default_environment[index];
}
uchar env_get_char_memory(int index)
{
return *env_get_addr(index);
}
uchar env_get_char(int index)
{
/* if relocated to RAM */
if (gd->flags & GD_FLG_RELOC)
return env_get_char_memory(index);
else
return env_get_char_init(index);
}
So I conclude that inherently, u-boot code there is no possibility to point the mmc area where environments are stored.
Can anyone confirm this?
I would like to implement a main function such as in order to execute system commands. The following code is currently used :
int main(int argc, char *argv[])
{
size_t cmd_length;
char *cmd_buffer = NULL;
char *file = NULL;
char *ip = NULL;
int size;
if(argc == 3)
{
size = strlen(argv[1]);
file = (char*)malloc((size + 1)*sizeof(char));
strcpy(file, argv[1]);
size = strlen(argv[2]);
ip = (char*)malloc((size + 1)*sizeof(char));
strcpy(ip, argv[2]);
}
cmd_length = snprintf(NULL, 0, "tftp -g -r %s %s", file, ip);
cmd_buffer = malloc(cmd_length + 1);
if (cmd_buffer == NULL)
{
return -1;
}
snprintf(cmd_buffer, cmd_length + 1, "tftp -g -r %s %s", file, ip);
if(system(cmd_buffer) == 0)
{
then ...
}
{
return -1;
}
free(cmd_buffer);
cmd_buffer = NULL;
cmd_length = snprintf(NULL, 0, "tftp -g -r %s %s", DFT_FILE, DFT_IP);
cmd_buffer = malloc(cmd_length + 1);
if (cmd_buffer == NULL)
{
return -1;
}
snprintf(cmd_buffer, cmd_length + 1, "tftp -g -r %s %s", DFT_FILE, DFT_IP);
if(system(cmd_buffer) == 0)
{
then ...
}
{
return -1;
}
free(cmd_buffer);
free(file);
free(ip);
cmd_buffer = NULL;
file = NULL;
ip = NULL;
return 0;
}
Because I need to enter other commands, I am currently using the same cmd_buffer by using free() before reallocating memory. Is it the right way to do ? Some other commands might be required in the future.
Your program can be be greatly simplified if you use a common function to execute the system call. It doesn't even need to use malloc at all. Here's a partial implementation [Please pardon the gratuitous style cleanup]:
#include <stdarg.h>
int
execute_command(const char *fmt,...)
{
char cmd_buffer[5000];
int cmd_length;
va_list ap;
// NOTE: much simpler to used a fixed size buffer that is larger than
// needed
va_start(ap,fmt);
cmd_length = vsnprintf(cmd_buffer,sizeof(cmd_buffer),fmt,ap);
va_end(ap);
if (system(cmd_buffer) != 0)
return -1;
return 0;
}
int
main(int argc, char *argv[])
{
char *file = NULL;
char *ip = NULL;
// NOTE: I had to guess the intent if fewer arguments are passed (e.g. just
// skip as I did here, print message and abort?)
if (argc == 3) {
// NOTE: no need to malloc these, but if you did, see strdup(3)
file = argv[1];
ip = argv[2];
execute_command("tftp -g -r %s %s", file, ip);
}
execute_command("tftp -g -r %s %s", DFT_FILE, DFT_IP);
return 0;
}
Yes, you are essentially just re-using the pointer variable cmd_buffer which is fine. And for every malloc() there is a matching free(), which is good.
You should factor our common code into a function, for example runCommand(const char *command, ...) (using varargs).
I have written a program (with code from SO) that does printenv | sort | less and now I should implement error-handling. How can that be done? The program should fail gracefully, for example when passed the wrong arguments.
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct command
{
const char **argv;
};
/* Helper function that spawns processes */
int spawn_proc (int in, int out, struct command *cmd) {
pid_t pid;
if ((pid = fork ()) == 0) {
if (in != 0) {
dup2 (in, 0);
close (in);
}
if (out != 1) {
dup2 (out, 1);
close (out);
}
return execvp (cmd->argv [0], (char * const *)cmd->argv);
}
return pid;
}
/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
int i;
int in, fd [2];
for (i = 0; i < n - 1; ++i) {
pipe (fd);
spawn_proc (in, fd [1], cmd + i);
close (fd [1]);
in = fd [0];
}
dup2 (in, 0);
return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}
int main (int argc, char ** argv) {
int i;
if (argc == 1) { /* There were no arguments */
const char *printenv[] = { "printenv", 0};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {sort}, {less} };
return fork_pipes (3, cmd);
}
if (argc > 1) { /* I'd like an argument */
if (strncmp(argv[1], "cd", 2) && strncmp(argv[1], "exit", 2)) {
char *tmp;
int len = 1;
for( i=1; i<argc; i++)
{
len += strlen(argv[i]) + 2;
}
tmp = (char*) malloc(len);
tmp[0] = '\0';
int pos = 0;
for( i=1; i<argc; i++)
{
pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
}
const char *printenv[] = { "printenv", 0};
const char *grep[] = { "grep", "-E", tmp, NULL};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
return fork_pipes (4, cmd);
free(tmp);
} else if (! strncmp(argv[1], "cd", 2)) { /* change directory */
printf("change directory to %s\n" , argv[2]);
chdir(argv[2]);
} else if (! strncmp(argv[1], "exit", 2)) { /* change directory */
printf("exit\n");
exit(0);
}
}
exit(0);
}
It's going to be frankly a bit painful to go through your program and fix all those missing-error-handling bugs after the fact. Much better would have been to write correct code from the start! Moreover, you have more bugs than just missing error handling. I didn't scan all of your code, but at first glance I already saw one use of an uninitialized local variable (in in fork_pipes is used before it is set). Any decent compiler with warnings enabled would have caught that.
As a direct answer to your question, you'll just have to go through and spot every system call or library function call that is capable of returning errors, see if you are checking for them, and add checks if they are not already there. fork, malloc, dup2 — everything.
I coded a strcat function. But my function doesn't run in this way -----> char * mystrcat(char *s,char *t). I want to return a pointer. Can you help me?
#include <stdio.h>
void mystrcat(char *s,char *t)
{
while(*s!='\0')
s++;
s--;
while((*(s+1)=*t)!='\0')
{ s++;
t++;
}
}
int main()
{
char str[30], str1[30];
gets(str);
gets(str1);
mystrcat(str, str1);
printf("%s\n",str);
return 0;
}
Your function has no return value. If you want to return a pointer from it then just return it. And also void is incorrect for that
When you write void mystrcat(char *s,char *t) you are saying "I will not have a return value" by using void. If you want to return a pointer, this must not be void.
To return a pointer to your string, use char**.
Your string, a series of characters, is represented as a char*.
Here's an example using your code.
#include <stdio.h>
char** mystrcat(char *s,char *t)
{
char *sOrig = s;
while(*s!='\0'){
s++;
}
s--;
while( ( *(s+1) = *t) != '\0')
{
s++;
t++;
}
return &sOrig;
}
int main()
{
char str[30], str1[30];
gets(str);
gets(str1);
char** concatValuePointer = mystrcat(str, str1);
printf("Pointer is %p\n",concatValuePointer);
return 0;
}