Execv for own terminal - c

I am currently writing my own terminal in C.
I found out, that there is multiple variants of the exec() methode, that i can use.
Its simple occurance lead me to use execv():
int main(int argc , char* argv[]){
char* dir = getcwd(NULL, 0);
char* command[] = {"echo", "Hello", "World", "!!!", NULL};
execv(dir, command);
}
From my understanding this should work. It is compiling, but nothing happens.

The path argument to execv is supposed to be the path specification to the executable file you want to run, not just a directory as returned by getcwd. From the manpage:
The initial argument for these functions is the pathname of a file which is to be executed.
In other words, you're looking for something like:
execv ("/bin/echo", command);
The code you currently have is trying to run your current directory, something that's unlikely to end well, and something you may have noticed if you checked the return value from execv along with errno: nudge, nudge, wink, wink :-)
In terms of what to do for other programs, you simply substitute their full path name for /bin/echo.
You should also be aware that exec is a family of functions, each with slight variations.
Some allow environments to be passed, some automatically search the path for your executable (depending on the name given), and some use variable argument lists rather than arrays. If you want to use the automatic path searching, you would look into execvp rather than execv, then you don't have to worry about where the executable file is located.

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.

Command line arguments without the hyphen

How can I parse arguments without the hyphen in C?
I.e. virsh install vm
or
git pull origin master
When I tried it out, if there is no - prefix, everything just gets ignored and argc returns 1 (argv[0] is the program call).
I'm using Linux, but it would be nice if there was a cross platform method to achieve this.
UPDATE: the problem was me using a # in front of the first argument, I was trying to pass in #XX eg number_program #12. Needless to say this doesn't work.
Are you using some library to parse the arguments for you? There is no special 'hyphen' arguments when passing in parameters to a C program specifically. Parse argv however you like.
For example:
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for(i=0; i<argc; i++) {
//dont do this without proper input validation
printf("%s\n", argv[i]);
}
return 0;
}
Example run:
$ ./a.out test test test -hyphen
./a.out
test
test
test
-hyphen
argv contains the program name and the arguments to the program, in the order they were given in the command line.* Hyphens aren't special; they just make it easy for both people and computers to separate options from other args.
If you want to interpret args a certain way, that's your prerogative. That's what git does, basically interpreting argv[1] (if it exists, of course) as the name of a subcommand. And you don't need any libraries in order to do that. You just need to decide how you want the args interpreted.
* Modulo some cross-platform differences in how args are parsed; *nix typically does some pre-parsing for you and expands wildcard patterns, for example. You won't have 100% cross-platform compatibility unless you understand those differences and are ready for them.

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.

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