So the following snippet should either make the prompt in a simple shell program 'my257sh'>, or ''> if -p is used as a command line arg when launching, followed by a string to be used as the custom prompt.
The custom prompt works fine, but I get a seg fault when launching with no additional args.
Can someone tell me what incredibly simple and stupid thing I'm doing wrong?
int main(int argc, char *argv[]) {
char cmdline[MAXLINE]; /* Command line */
char def_prompt[20] = "my257sh";
const char prompt_check[2] = "-p";
char new_prompt[20];
if (argc > 0){
if (strstr(argv[1], prompt_check)) {
strcpy(new_prompt, argv[2]);
}
}
else {
strcpy(new_prompt, def_prompt);
}
signal(SIGINT, sigIntHandler); // ignores ctrl + C interrupt
while (1) {
/* Read */
printf("%s> ",new_prompt);
...
argc is always > 0 : argv[0] contains the name of the program.
Check
If argc > 1
Also in case of -p check that
If argc > 2
You also need to check the length of prompt to avoid copying in too small string
argc contains the number of arguments passed on the shell, including the command itself, so argc will always be > 0 as it is at least 1 if no parameters were given.
If you don't pass any arguments, then argv[1] will contain a NULLpointer. If you pass only one parameter then argv[2] is a NULL pointer.
if (argc > 2)
{
if (strstr(argv[1], prompt_check))
strcpy(new_prompt, argv[2]);
}
else
{
strcpy(new_prompt, def_prompt);
}
Related
I'm having a slight issue with my current piece of code and trying to check that arguments have been passed to enum before trying to continue with the program;
enum arg {argName, sineArg, sampleArg, argC}eargs;
int main(int argc, char *argv[]){
long samplingRate = atol(argv[sampleArg]);
float sineFreq = atof(argv[sineArg]);
if (argC < eargs ){
printf("Usage: sineFreq\tsamplingRate\n");
}else{}
}
The code compiles fine, although when run without arguments the program returns "Segmentation fault: 11" instead of the usage message that I want to print to console.
you have to do the check before accessing argv[...]
EDIT: the check itself is wrong too (eargs is undefined; you should write
int main(int argc, char *argv[]) {
if (argc < argC) /* --> you should change you naming conventions! */
return EXIT_FAILURE;
long samplingRate = atol(argv[sampleArg]);
Your usage check is against eargs that has nothing to with the number of command line arguments passed. No matter how many arguments you pass, eargs is always going to be 0.
Also you should do the check before using any of the command line arguments. Place the condition at the start of main():
#include<stdio.h>
#include <stdlib.h>
enum arg {argName, sineArg, sampleArg, argC}eargs;
int main(int argc, char *argv[]) {
/* if ( argc < 3) would be explicit and clear here */
if (argc < argC ) { /* You expect at least two arguments */
printf("Usage: sineFreq\tsamplingRate\n");
return 1; // return from main on failure
}
long samplingRate = atol(argv[sampleArg]);
float sineFreq = atof(argv[sineArg]);
....
}
I have also included standard headers as you are using printf() and atol()
you need to change argC to argc, in the if statement...c is case-sensitive!!!
When you run the code without arguments, this
long samplingRate = atol(argv[sampleArg]);
accesses argv[2], which is undefined behavior, since you don't provide enough args (there are only argv[0] = program name and argv[1] = NULL indicating the end of the argv[]).
I am reading the book Windows System Programming. In the second chapter, there is a program Cat.c. It implements the cat command of linux. The code is http://pastebin.com/wwQFp599
Here is the part in which confuses me:
/* iFirstFile is the argv [] index of the first input file. */
iFirstFile = Options (argc, argv, _T("s"), &dashS, NULL);
if (iFirstFile == argc) { /* No files in arg list. */
CatFile (hStdIn, hStdOut);
return 0;
}
As mentioned in the comment iFirstFile is the argv [] index of the first input file.
It means if I try cat -s abc.txt, then iFirstFile = 2, but argc == 3.
I can't think in what circumstance iFirstFile == argc ? I can't understand the logic behind it. Can anyone explain me this part?
Like it says in the comments, if there are no filenames in argv, then Options() returns argc. So this is the case where you want to cat stdin and not a file.
if (iFirstFile == argc) { /* No files in arg list. */
CatFile (hStdIn, hStdOut);
return 0;
}
For example "cat > x" reads from the stdin. So does "foo | cat | bar". In each of these cases Options() would return argc;
If you run the program with:
cat
Then argc == 1 and iFirstFile == 1. Therefore the if statement condition will be true and it will run using stdin and stdout, allowing the use of pipes or interactive input, or output to the terminal window.
I'm working on a project that basically does the same thing as strace(1) using ptrace(). Basically we have a controller.c program that takes an executable as an argument and it outputs any system calls made by the executable (for example % controller ls -l)
We are using the execve() to run the executable file, but we are having a little bit of trouble. execve takes the following arguments
execve( const char *filename, char *const argv[], char *const envp[] )
where filename in this instance would be "ls", and argv[] is a list of the arguments for the given file name. So we have something that looks like this (in the C file)
int main(int argc, char *argv[],char *envp[]){
pid_t child;
child = fork;
if(/* CHILD */){
ptrace(PTRACE_TRACEME,0, NULL, NULL);
if(argc == 2) {
execve(argv[1],NULL,envp);
}
else {
execve( argv[1], /* ARGUMENT LIST */, envp);
}
} else /* PARENT */ {
//PARENT CODE
}
}
So if we get an executable, for example controller ls -l, where argv[0] = "controller", argv[1] = "ls", and argv[2] = "-l", how can we pass the correct parameter at "ARGUMENT LIST" (where the arguments in this case is just "-l" but it could be more)?
Basically, how do we initialize an array of type const char * such that the array has the argument values for the executable? Do we even need to worry about having extra values in the array and just past argv for ARGUMENT LIST?
Thanks for your help!
You can simply pass argv + 1 (to skip your program's name). argv + 1 is a pointer to an array starting from the second element of argv, which is the executed program's name. argv + 1 is equivalent to &argv[1], and you can use whatever style you prefer.
As mentioned in the comments, section 5.1.2.2.1 of the standard specified that argv is indeed null-terminated. The section below is retained for completeness.
In case C doesn't guarantee argv is null-terminated (and it's not clear to me whether it does or not), you can do:
char **new_argv = malloc((argc-1) * sizeof(char*));
for (int i = 0; i < argc - 1) new_argv[i] = argv[i+1];
and use new_argv for the argument list.
execve(argv[1], argv+1, envp);
I've separated a given command from the user into substrings , here's the code :
int i;
char *line = malloc(BUFFER);
char *origLine = line;
fgets(line, 128, stdin); // get a line from stdin
// get complete diagnostics on the given string
lineData info = runDiagnostics(line);
char command[20];
sscanf(line, "%20s ", command);
line = strchr(line, ' ');
printf("The Command is: %s\n", command);
int currentCount = 0; // number of elements in the line
int *argumentsCount = ¤tCount; // pointer to that
// get the elements separated
char** arguments = separateLineGetElements(line,argumentsCount);
// here we call a method that would execute the commands
if (execvp(*arguments,*argumentsCount) < 0) // execute the command
{
printf("ERROR: exec failed\n");
exit(1);
}
When I execute the command in execvp(*arguments,*argumentsCount) , it fails .
What's wrong ?
Thanks .
EDIT :
The input from the user is : ls > a.out , hence I have 3 strings , which are :
ls , > , a.out , and it fails .
Shell redirection won't work if you aren't invoking a shell. You also won't have path searching to find the ls program. Some options
use system() instead, and exit when it returns
exec a shell and have it run your command
setup redirection as a shell would, then fork and execute each required child program.
Also your command doesn't make a lot of sense, you probably want ¦ instead of > and may need to specify the directory of a.out if it is not in your path. Consider giving it a meaningful name as well.
From man page of execvp command:
int execvp(const char *file, char *const argv[]);
The second argument is a list of null-terminated C-strings as arguments to the command to be executed by execvp. But in your code, you pass an int as the second argument which is wrong.
If you have list of arguments in the variable arguments then call execvp as:
execvp(arguments[0],arguments);
When you run ls > a.out at the command-line, > and a.out are not arguments passed to the application; they're interpreted by the shell to redirect stdout.
So in short, it is not possible to do what you want to do.1
1. Well, it is, but not this way. Your application would need to interpret the arguments, create the file, and set up a stream redirect.
While trying to take some arguments for C. I found it really difficult to get argv[] to work. I have:
int main(int argc, char *argv[])
{
void updateNext();
void fcfs();
void spn();
void srt();
fp = fopen(argv[0],"r");
op = fopen("output.dat","a+");
if (strcmp(argv[1],"FCFS")!=0)
{
fcfs();
}
if (strcmp(argv[1],"SPN")!=0)
{
spn();
}
if (strcmp(argv[1],"SRT")!=0)
{
srt();
}
}
I would like to enter something in a format of myprog input.data FCFS, but the above code gives me an error for "float point exception" the exception is gone after I hard code input.dat as a string in the program. Something wrong with argv[0] perhaps?
In C, argv[0] is the name of your program (or more precisely, the first word the user typed on the command line to run your program, if run from a shell).
So, avoiding argv[0] for your purposes, you'll want to look at argv[1] for the file name and argv[2] for the other parameter.
This would have been clear if you had used a debugger to trace through your program, or simply printed the value before you used it:
printf("using file name %s\n", argv[0]);
fp = fopen(argv[0],"r");
It's also a good idea to check that you have sufficient command line parameters by validating argc before accessing argv:
if (argc < 3) {
fprintf(stderr, "not enough command line parameters\n");
exit(1);
}
In C argv[0] is typically the name with which the program was called. You're looking for argv[1] and argv[2].
As side notes:
you should be checking argc before touching argv
there's no guarantee argv[0] contains the name of the program or even something sensible