How does one create a function that takes another command as an argument and executes that command. For example say I wanted to do
./func1 cat /etc/motd
and have it execute the cat command on the file /etc/motd so that it would print the message of the day. If someone could show me that would be much appreciated!
EDIT: I cannot use the system() call as later on I have to program a basic command shell. I just need to know how to execute commands so that when a user types in cat foo.txt it executes the command and displays the file. I guess what I'm trying to say is, how do you use execve()? What arguments go inside it?
Use you can use the system function.
Example:
system("cat foo.txt");
Will run this:
cat foo.txt
You could do something like that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
size_t command_length = 0;
if(argc < 2)
return 0;
for(int i = 1; i < argc; i++)
command_length += strlen(argv[i]);
command_length += argc - 2; // spaces between words
command_length++; // terminator '\0'
char command[command_length];
memset(command, 0, sizeof(command));
for(int i = 1; i < argc; i++) {
strcat(command, argv[i]);
if(i < argc - 1)
command[strlen(command)] = ' ';
}
system(command);
}
It first determines the length of all command line parameters. After that it concatenates all command line parameters and inserts a space between each. Last but not least it calls the system() function with this string.
You need to use a C11 compiler with VLA support.
Here is a version without system():
#include <string.h>
#include <unistd.h>
#define MAX 1024
int main(int argc, char *argv[]) {
char buf[MAX] = "/usr/bin/";
size_t len = MAX - strlen(buf) + 1;
if(argc < 2)
return 0;
strncat(buf, argv[1], len);
execve(buf, argv + 1, NULL);
return 0;
}
This program only works under Linux. Unfortunately the execve() expects an absolute path. I assumed that the executable is located under /usr/bin. Additional work is necessary if that's not the case. For example you would have to examine the $PATH environment variable.
Related
I would like to get argv from an LD_PRELOAD library, for instance, let us assume we call
LD_PRELOAD=/path/to/my/fopen ./program input
Inside my custom fopen I would like to get "input", hence the argv[1] of my program (also the argv[2] and so on).
Is it possible? How?
Read entire /proc/self/cmdline file. Command line arguments are separated with \0.
See man proc for full details.
Linux example without C standard library or error handling:
#include <unistd.h>
#include <fcntl.h>
#include <linux/limits.h>
int main() {
ssize_t i, n;
char cmdline[ARG_MAX];
int cmdline_fd = open("/proc/self/cmdline", O_RDONLY);
n = read(cmdline_fd, cmdline, sizeof cmdline);
for(i = 0; i < n; ++i)
if(!cmdline[i])
cmdline[i] = ' ';
cmdline[n - 1] = '\n';
write(STDOUT_FILENO, cmdline, n);
return 0;
}
Python version for reference:
cmdline = open('/proc/self/cmdline', 'r').read().replace('\0', ' ').strip()
print(cmdline)
I am trying to build an echo-like command which I named code at xv6. The problem is that if:
Input:
$code Hello World
Output:
user space:Hello user space:World
While the correct output should be:
user space: Hello World
Can somebody help me?
int
main(int argc, char *argv[])
{
int i;
if(argc <= 1){
printf(1," %s user space:", argv[0]);
exit();
}
for(i = 1; i < argc; i++){
printf(1, " print in user space:%s",argv[i]);
}
printf(1, "\n");
exit();
}
program name is also passed as argument to your main function so you have three(as hello and world are considered separate arguments) arguments here .there is several issues in your code ,as you have two arguments first if statement will be false ,and you are not printing correctly in for loop ,following might be helpful :
int main(int argc, char *argv[])
{
int i;
printf("number of arguments : %d ",argc);
//argv array index count from 0
for(i = 0; i < argc; i++){
printf("argument number %d : %s",i,argv[i]); // issue in your code
}
printf("\n");//issue in your code
exit(0);
}
It's possible to use the write command so that you can output to stdout. Between each command line argument an additional space needs to be written.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i;
write(1, "user space: ", 12);
for (i = 1; i < argc; i++) {
size_t len = strlen(argv[i]);
write(1, argv[i], len);
write(1, " ", 1);
}
write(1, "\n", 1);
return 0;
}
The problematic part in your code is here:
for(i = 1; i < argc; i++){
printf(1, " print in user space:%s",argv[i]); //" print in user space:" is printed
//for each iteration
}
As others pointed out, you should rather do:
printf(" print in user space:\n");
for(i = 1; i < argc; i++){
printf("%s",argv[i]);
}
That said, a few more remarks for you:
I never seen a printf that takes an integer as first argument, I assume that the first parameter is not important/is a typo
I am not an expert unix developer, but you can just use "return 0" (or "return 1") to quit your program. You will also be able to return an error code this way, as most unix programs do
If you decide to use printf, be aware that it comes with a nasty security exploit which can expose the caller's stack to a malicious user. Make sure your input is well formed or use a different function if possible
First of all, I am talking about old-fashioned ANSI-C (I mean the ANSI standard and no C99 or newer) compiled with gcc. I am only allowed to use the libraries that can be seen below in the code.
My problem is I have a program that is called in the following way on the Terminal:
program < integer_1 integer_2
While I have been able to figure out how to check for the number of arguments, I'm stuck on checking if those are integers.
If the program is called like this:
program < 1 -13
it should run without complaining but if it is run like this:
program < s 7
it should throw out an error.
Whatever I have tried so far has been utter rubbish. The best thing I have managed so far has been an error message if the second number has been a character. None of my tries has been able to deal with more than one digit but I have figured out why that is.
The problem is that I haven't used command line / terminal arguments with any programming language i now (C++, Java). I would really appreciate it if someone could show me how check for correct input as frankly I am out of ideas.
Am I correct that if I want to deal with numbers bigger than 9, I have to iterate through argv starting from index 2 until I find a space?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int arc, char *argv[])
{
if(arc != 3)
{
printf("Error: You have entered %d arguments, but two were expected!", arc - 1);
return -1;
}
return 0;
}
The easiest way out is to iterate over the argv[n]s and pass one by one to them to strtol() or similar. Then, check for the error and make the decision. To quote the man page, (emphasis mine)
long int strtol(const char *nptr, char **endptr, int base);
[...]
If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid.
That said, program < integer_1 integer_2 is not exactly the way to pass the command-line arguments. If you want to pass the values arguments as command-line arguments, you shall lose the redirection operator and work with argc and argv[n]s directly..
Best way is to create a function for checking whether it is number or not.if the below function returns true then use atoi(argv[]) to convert them to integers to use it further.
bool isNumber(char number[])
{
int i = 0;
//checking for negative numbers
if (number[0] == '-')
i = 1;
for (; number[i] != 0; i++)
{
//if (number[i] > '9' || number[i] < '0')
if (!isdigit(number[i]))
return false;
}
return true;
}
Just a comment: not an answer
If you are going to use
program < arg1 arg2
You will not see arg1 or arg2 in the main parameters. arg1 is typically a filename or device which contain data which will be read by the program. I don't know if the program will even be able to access arg2. If you wish to pick up arg1 arg2 etc, lose the <
program arg1 arg2
You can try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int check_cmd_args(char const *str[], int numargs);
int
main(int argc, char const *argv[]) {
if (argc < 2) {
printf("Not enough command line arguements entered\n");
exit(EXIT_FAILURE);
}
if (check_cmd_args(argv, argc)) {
printf("All Command line arguements are integers\n");
} else {
printf("Error, non-integer command line arguement entered\n");
}
return 0;
}
int
check_cmd_args(char const *str[], int numargs) {
int n, i = 0;
for (n = 1; n < numargs; n++) {
if (str[n][0] == '-') {
i = 1;
}
for (; str[n][i]; i++) {
if (!isdigit(str[n][i])) {
return 0;
}
}
}
return 1;
}
I'm making a very simple program code.
First, it has the option "-num" as 2nd argc. If you input anything in the 3rd argc, the program will simply say that the 3rd argc is entered.
Here are the examples of the inputs and outputs.
Input command line 1:
./test -num
Output 1
-num
Input command line 2:
./test -num AnythingHere
Output 2
-num 3rdArgcEntered
I also want the following command line with sticked argc (-num and AnythingHere are sticked together) to give the same output as Output 2:
./test -numAnythingHere
The output I wish to get is:
-num 3rdArgcEntered
But I obtained:
None
This is the source code I'm currently working on:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[])
{
if (!strcmp(argv[1], "-num"))
{
printf("-num ");
if(argc==3){
printf("3rdArgcEntered");
}
}
else
{
printf("None");
}
printf("\n");
return 0;
}
a little trash..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[])
{
/* doesnt check when args are not entered */
char *tmp = argv[1];
char buff[5];
/* copy -num, doesnt check */
memcpy(buff, tmp, 4);
buff[4] = '\0';
if (!strcmp(buff, "-num"))
{
printf("-num ");
/* larger than -num */
if(argc==3 || strlen(tmp) > 4 ){
printf("3rdArgcEntered");
}
}
else
{
printf("None");
}
printf("\n");
return 0;
}
Your program can't affect how the arguments are passed; obviously main has already been called at the beginning of main. You need to parse each argument yourself, or use a library that does it for you. For parsing them yourself, you could look at strtok or sscanf, or iterate over the characters. But a more specific library, such as getopt, is generally preferable, since it makes it easy to get your program to behave in a manner consistent with other command-line utilities.
I have a task to write a c program that can search for a directory in all the directories listed in $PATH using fork and exec. My question is how do i get the paths from $PATH in a manner that i can then use it in my code with execl
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char* argv[]) {
int pid = 0;
for(int i = 0; i < argc; i++) {
if (pid = fork() != 0){
printf("Arg%d: %c\n", i, *argv[i]); // replace with exec ls -l <dir>/<arg>
return 0;
}
}
return 0;
}
You can get the PATH environment variable using getenv() (man 3 getenv). Copy the string into a char* and then split it with strtok() (man 3 strtok) using ':' as delimiter. You should copy the original string into a new char* because the pointer you get from getenv() actually points inside the environment and strtok() will modify the argument you pass to it. You can then fork in a loop for each substring.