Execute bootm command in C - u-boot

For context, I've been adding some patches to u-boot for a project, and I already have the kernel image, device tree blob, and initrd image loaded into u-boot memory.
I've had luck in the past calling command line functions (like do_mem_cp) through their respective C functions, but I am not having luck with the bootm command. I am currently doing:
char *argv[4] = {"bootm", "a5001000", "b0000000", "a9000000"};
do_bootm(NULL, 0, 4, argv);
As I stated, this worked in the past for other commands, but during this call I'm getting the error "Synchronous Abort" handler, esr 0x96000004. Does anyone know of a better way to call bootm (or a similar command) from C?
Edit: This is for the Jetson TX2i

The definition of do_bootm() is:
extern int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
In case of an error cmdtp is dereferenced to print the name of the executed command. So you should not pass NULL as cmdtp. Instead fill a structure of the appropriate type and pass a pointer to it.

Related

Open a file in C

I am trying to write a tiny program in C that will open a file and then run the filename in terminal to stream the file to my Apple TV.
The reason I want to do this is so I can right click a media file, select 'Open With', choose 'Apple TV' from the list and then have it stream to my Apple TV via the airstream program.
My code so far is as follows
#include <stdio.h>
#include <string.h>
int main ()
{
char command[50];
strcpy( command, "airstream '/home/steve/media.mp4' -o 192.168.0.2" );
system(command);
return(0);
}
Very simple, but I'm not sure how to handle a file being passed to the application to allow it to get the filename and modify the command.
(First, let me make a comment on strcpy(): as-is, the call to strcpy() is superfluous (and imposes a security issue), because you are using a constant string. You could have written system("airstream '/home/steve/media.mp4' -o 192.168.0.2") instead.)
If you want to construct a command given a filename, you could in theory write
char command[LINE_MAX];
snprintf(command, sizeof command, "some_command %s", argv[1]);
system(command);
But that again rises a security problem, because now your program can be hijacked to execute an arbitrary external program, by passing it a malformed command-line argument, similarly to an SQL injection attack.
You'd be better off finding the library/API the airstream executable uses, and incorporate that directly into your program. If no such thing exists, you have to make sure to at least validate the user input (i. e. escape special characters, etc.) before handing it over to the shell for execution.
You need to use the arguments passed to the main() function. Change the function's signature to:
int main(int argc, char *argv[])
Then loop over the string pointers in argv[], which will be the command-line arguments your program was given.

List a target directory in C

So I am tasked with creating a shell. I have the functions working correctly (e.g. dir, clear, quit, etc.), but I have a question about the 'dir' function. Currently 'dir' works fine. It lists the files of the directory that the program is located in. What I want to do is list the directory of another location. Is there a way to that?
I have yet to create the change directory command. I was wondering if my problem would be solved through that instead. Any help is appreciated.
Side note: The instructions state that I "will need to provide some command line parsing capability to extract the target directory for listing." I have no idea what that is, but maybe someone could enlighten me.
Take a look at GNU's Simple Directory Lister example code, which uses opendir().
To parse command line arguments, take a look at your main() function:
int main(int argc, char* argv[])
{
...
return 0;
}
Use the argv[] pointer and argc integer value to determine the number of and character pointers of arguments.

Distinguish between optional arguments, pathname or file? c language

I am very new with c and less experienced with any other language :/
For an assignment at uni, I am a little stuck on this small part. Essentially I am required to write a 'ls' function that has 4 optional arguments, for example:
list [-l] [-f] [pathname] [localfile]
Now, the first two are straight forward. To make things more difficult, the 'localfile' doesn't necessarily exist and the 'pathname'(if given) will be located on the server I'm connecting to through a socket (so checking if it is a file is out and checking the pathname is out). I was thinking, check last 4 chars in the string for a '.txt' or something similar. I'm actually completely stumped and will present this problem to my course conveyor tomorrow, if I can't find a solution.
This is a very small part of what I actually have to do but any push in the right direction would be appreciated.
You will need to process argc and argv to get your command line arguments. That is the first thing to work on, getting the arguments - ensuring they are correct, and determining what is being asked for.
int main(int argc, char *argv[])
Assuming your are on Linux/Unix, you will need to use the directory functions opendir()/readdir()/closedir() - dirent.h. The stat() function will be required to satisfy the -l requirement. access() will determine if a file exists and then stat() will tell you if the file is a regular file or a directory.
I'd make a struct to hold the four optional arguments and return it from a function called "process_arguments" that takes argc and argv as parameters.
struct args {
bool valid;
bool l_option;
bool f_option
char directory[200];
char filename[200];
}
With the requirement for a socket connection you will have to write a "server program" that will be constantly running on the server and a "client program" that it will fork to handle the requests from your local program. Try and locate examples of socket programs.
Another check for whether you have a path string or a filename is to look for the path separator character - '/' if the server is Unix/Linux. This scheme shouldn't have any path separators in filenames, so the presence of one tells you it is a path.

How to make gdb follow execv? Not working despite "follow-exec-mode"

i've written two simple programs:
int main(int ac, char **argv ) {
execv( "/home/me/Desktop/execvtest2", argv );
}
and
int main(int ac, char **argv ) {
execv( "/home/me/Desktop/execvtest1", argv );
}
I've compiled them with
gcc -g to the according outputfiles.
I'm running Ubuntu 10.10 using gcc (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5.
When I'm debuging the first program with GNU gdb (GDB) 7.2-ubuntu, I can step until the first execv statement, but then the two files just keep running. Even if I set the follow-exec-mode to new, I can't step into the second program.
When I set catch exec, gdb stops at each call to execv (some how without linked source for the second program, and I'm not able to quit gdb, as it kind of hangs!?), but I'm not able to step over the call into the "new" (as exec replaces the process) inferior program.
So how can this be done? There must be a way to step into the new process right? Am I doing something wrong?
Cheers
you can use "catch" command.
this will give you chance to put some break points
after you exec
I've been doing something very similar to what you are doing for one of my classes. It is a bit hackish and if you're trying to get things like register values it may mess things up. According to GDB's documentation you can change the symbol file while maintaining the execution file. To do this, simply use the command symbol-file file2.
Note that this must be a binary file compiled with the GDB flag (-g in GCC). After you've loaded this symbol file, you will not be able to break or see any of the lines for the original execution file. However, you may set break points for the new symbol file i.e. break file2.c:40 and then step through execution just as before. It is a bit hackish and may not work perfectly because you are essentially catching the execution of a new process and mapping it to the symbol table of it's binary file, without using that binary file to run it directly. I haven't had stellar results but you can see the intermediate values this way.
Another thing, in order to return to debugging the original file you will have to do symbol-file file to reload it's symbol table.

understanding requirements for execve and setting environment vars

We are having a lot of trouble interpreting our teacher. We asked for clarification and got the following back from him
For execve, send it a environment you setup with your exported variables and create a builtin command to spawn a subshell of /bin/bash, that way you can see your exported variables using env.
(He is talking about creating our own environment vars here.)
Yes create your own. You can start by copying environ when your shell starts and add only exported variables
This is related to the following post on Stack Overflow by me (reading this other post will help you understand what I am trying to do):
using a new path with execve to run ls command
We are just very confused about this. One more time I will explain what we are trying to do now. Similar to how your Linux shell does this, we need to write our own program that can set environment variables like PATH and USER and whatever other vars the user wants to define.
An example of how you would call this would be (inside your program at its prompt):
mysetenv dog spike
which would create an environment variable looking like "dog=spike"
More importantly, we need to be able to set our own PATH variable and send it to an exec command. This is the confusing part because, based on all of our questions, we don't understand what we are supposed to do.
It is actually very simple. You already know that your arguments are a list of char *, terminated by a NULL pointer. Similarly, the environment is simply a list of char *, terminated by a NULL pointer. Conventionally, the values in the list take the form VARNAME=var-value, though you can pass other formats if you wish.
So, to take a simple case:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
char *argv[] = { "/bin/sh", "-c", "env", 0 };
char *envp[] =
{
"HOME=/",
"PATH=/bin:/usr/bin",
"TZ=UTC0",
"USER=beelzebub",
"LOGNAME=tarzan",
0
};
execve(argv[0], &argv[0], envp);
fprintf(stderr, "Oops!\n");
return -1;
}
In this example, the program will run /bin/sh with arguments -c and env, which means that the shell will run the env program found on its current PATH. The environment here is set to contain 5 values in the orthodox format. If you change env to date (or env; date), you will see the effect of the TZ setting, for example. When I run that on my MacOS X machine, the output is:
USER=beelzebub
PATH=/bin:/usr/bin
PWD=/Users/jleffler/tmp/soq
TZ=UTC0
SHLVL=1
HOME=/
LOGNAME=tarzan
_=/usr/bin/env
The shell has added environment variables SHLVL, _ and PWD to the ones I set explicitly in the execve() call.
You can also do fancier things, such as copy in some of the other environment variables from your genuine environment where they do not conflict with the ones you want to set explicitly. You can also play games like having two values for a single variable in the environment - which one takes effect? And you can play games with variable names that contain spaces (the shell doesn't like that much), or entries that do not match the 'varname=value' notation at all (no equals sign).
I'm a little late to the party here, but if you want to preserve the old environment variables as well as creating your own, use setenv, and then pass environ to execve().
setenv("dog", "spike", 1);
extern char** environ;
execve(argv[0], argv, environ);
environ is a variable declared in unistd.h, and it keeps track of the environment variables during this running process.
setenv() and putenv() modify environ, so when you pass it over execve(), the environment variables will be just as you'd expect.
The code from Jonathan Leffler works great, except if you want to change the PWD (working directory) variable.
What I did, in order to change the working directory, was to put a chdir(..) before execve(..) and call:
chdir("/foo/bar");
execve(argv[0], &argv[0], envp);

Resources