How does one get the raw command line in C under Linux? - c

I'm attempting to create a simple C program to dump the raw command line to debug the output of programs that call other programs. Here is what I have so far:
#include <stdio.h>
int main (int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
fprintf (stderr, "%s ", argv[i]);
fputs ("\n", stderr);
return (0);
}
There are several problems with this method. First of all, I have to insert a space manually after every argument. Secondly, the qouting on the original command like is lost, so with input like this:
./argvdump "'something'" """'"'""""other things""""'"'"""
I get output like this:
./argvdump something other things
which isn't very useful for debugging since I can't see what was actually on the command line.
Does anyone know how to get the actual raw command line?

The OS (or more specifically the shell) is the piece doing things like removing whitespace and quotes. There is no way to reconstruct the whole command line including all of those artifacts.
You could assume that if an argv member contains a space then originally it had quotes around it...

Related

Why isn't redirected input considered a command line argument?

I'm trying to read command line arguments that have been redirected from a file. The command I'm using is ./a.out < test.txt
And the contents of test.txt is: Hello world.
But the output of my program below isn't printing Hello
world. Instead it is only showing ./a.out. Why is this?
int main(int argc, char* argv[], char* envp[]) {
for (int i = 1; i < argc; i++) {
printf("%s\n", argv[i]);
}
}
The shell intercepts the redirection commands before preparing the command line for the program:
myProg <infile -t >outfile
will pass to the program
myProg -t
with stdin and stdout already rerouted before the pogram starts. So the program never sees the rediretion.
There a lot of cases, besides simple derirection:
dir > myfile.txt
Especially you can pipe output from one program to another:
dir | more
It will send output if dir command to more command. Since program launch handled by OS shell, it handles a redirection too.
Because the language is defined that way. Suppose what you say is true —
All the user input will have to come from command line arguments, but text redirected from a file can satisfy input required in different functions. This can be achieved if the input appears as command line arguments.
Consider this program:
#include <stdio.h>
int is_dict(char *word)
{
/* code to look up a dictionary */
int result = 1;
return result;
}
int main(int argc, char *argv[])
{
if(argc == 2 && is_dict(argv[1]))
printf("%s found", argv[1]);
return 0;
}
If the program is written that way to accommodate it, then the input would have to come from the command line arguments. How would you take input when it is not redirected? It would require more program overhead to detect the missing inputs.
Moreover, imagine a text file containing a million words: it is unfeasible to expect each word to arrive as an argv[n].
There are other objections too. Suppose the program prints a series of prompts for responses. The user would have to know in advance what the prompts are, to supply the answers before the prompts appear.
Lastly, if the program is run from a GUI, then all the program's input will have to be edited into its properties before it is run.

unix: main() interactive, command line, piping & redirection in C?

While there is an easy way of using both file redirection and piping, as well as interactive user input reading , with main(), as shown in this C code snippet...
#define SIZ 1024
#include <stdio.h>
extern void do_something_with_the_array(float *a[], int *n);
int main(int argc, const char * argv[])
{
float f[SIZ];
int k = 0;
while ((scanf("%f", &f[k]) == 1)&&(k < SIZ)) {
k++;
}
do_something_with_the_array(f, k);
return 0;
}
… I'm not sure if there is a modern UNIX source compatible and easy way of programmatically achieving any of the three possibilities in a main() in C, depending on the context ?
interactive reading of a string of numbers as user input
reading of the same string of numbers as command line arguments
file redirection and piping
I understand piping and redirection "belong" to the shell which intercepts the program before it even starts executing, while command line arguments and interactive reading "belong" to the main() itself and therefore there may not be an easy way of doing this.
I see using stdin or file input or pipe input pretty self-explanatory. However, reading command line arguments is a different story. Here's a demo how I usually code it, but it looks kind of heavy-handed and hacked to me. Also, in more complicated scenarios with options, this could become a pretty messy piece of code. I'm also not sure how fail-safe or fool proof this is...
#define SIZ 1024
#include <stdio.h>
#include <stdlib.h>
extern void do_something_with_the_array(float *, int);
int main(int argc, const char * argv[])
{
float f[SIZ];
int k = 0;
if(argc > 2){
for(k = 0; k < argc - 1; k++)
f[k] = (float)atof(argv[k+1]);
}
else while ((scanf("%f", &f[k]) == 1)&&(k < SIZ))
k++;
do_something_with_the_array(f, k);
return 0;
}
Thanks in advance!
I do not know off-hand of a C library that will make the three specific cases you mentioned look the same (although someone who does, please answer because I'd like to know, too!). I think you're looking for something not unlike the diamond <> operator in Perl, but for individual arguments rather than files containing arguments.
I think #David Hoelzer has the right idea: handle the three cases separately. For example, when processing command-line or file arguments, don't generate "Enter a value" prompts that you might print for interactive input. For command-line processing, getopt is a good place to start.
Now, a challenge to you: Wrap those three operations in a library and make it open-source so the rest of us can benefit! :)
Quite a few programs do care if they're invoked with keyboard input vs. file input, including the shell itself.
Let us take /bin/sh as our first example. If you call it directly, it starts an interactive shell, but if you pipe something into it, it starts as a non-interactive reading shell. The main difference between the two is if it is not interactive, it doesn't display the $ prompt. However just in case it really is interactive, it can be started with the -i option to make it assume its interactive when it would normally decide otherwise.
The magic involved here is isatty(); see man 3 isatty.
In addition, some programs like to receive keyboard input while processing redirected standard input. There are two generally favored ways of doing this; either opening and reading from /dev/tty or reading standard error, depending on context. Most stuff in an interactively started pipeline doesn't have standard error redirected, so this tends to work well (reading a redirected standard error yields an error immediately as the handle isn't open for read). If you want to make it potentially fully automatable, you read standard error, otherwise you read /dev/tty.

Segmentation fault when I pipe stdout to my program

I don't know if I have to tell it again, but english is not my native language and I'm not a very good student, I've seen you are able to correct my message so it's fine but I'd like to apologize once again.
Here is the deal, I have a program, which convert a given graph passed in argument to Dimacs format that I'll store in a .cnf file. (We use it to solve it with a SAT-solver)
He's perfectly working when I use it by myself, so I'd like to have another program, graph_generator, that I'll pipe into myprogram to have random graphes.
I've made my graph_generator program, and he correctly prints graph at the format I want, so I've tried to do basically ./graph_generator | ./myprogram but I instantly get a segmentation fault, I can't see why, graph_generator returns exactly what it's expected, and when I want to use a debugger, I don't see how it's possible knowing that I pipe a result, when I copy paste the result of graph_generator myprogram correctly generates my .cnf file.
I don't know where the problem could come from, I have a theory but it's a bit lame, it's that the stdout of graph_generator, once piped myprogram considers the space as an argument and there is the problem. Anyone could help me please?
int main (int argc, char* argv[]){
graph* mygraph;
int taille, nbEdge;
int i;
FILE* resultat;
printf("mark 1");
taille = atoi(argv[1]);
nbEdge = atoi(argv[2]);
printf("mark 2");
mygraph = build_empty_graph(taille);
for(i = 3; i < argc; i+= 2)
add_edge(atoi(argv[i]), atoi(argv[i+1]), mygraph);
resultat = fopen("resultat.cnf", "w");
write_result_comments(resultat);
write_result_header(resultat, mygraph);
write_first_stack(resultat, mygraph);
write_second_stack(resultat, mygraph);
fclose(resultat);
return 0;
}
Here is the main of myprogram, when I use it with the pipe, the message "mark1" doesn't even appears
It is segfaulting because you don't check argc and are passing no values as arguments.
Please note that stdin is a separate stream from the arguments in argv.
Best way to fix this is to build up hierarchically:
tokenizer: read stdin in a loop with getchar until you get to whitespace (space, tab or newline).
parser: atoi is fine, since you only pass ints.
state machine: first two args to taille and nbEdge, rest in pairs (x, y) to call the program. Maybe use a switch statement and a state variable in a loop.
program: the rest of your program pretty much as is.

Forking with command line arguments

I am building a Linux Shell, and my current headache is passing command line arguments to forked/exec'ed programs and system functions.
Currently all input is tokenized on spaces and new lines, in a global variable char * parsed_arguments. For example, the input dir /usa/folderb would be tokenized as:
parsed_arguments[0] = dir
parsed_arguments[1] = /usa/folderb
parsed_arguments tokenizes everything perfectly; My issue now is that i wish to only take a subset of parsed_arguments, which excludes the command/ first argument/path to executable to run in the shell, and store them in a new array, called passed_arguments.
so in the previous example dir /usa/folderb
parsed_arguments[0] = dir
parsed_arguments[1] = /usa/folderb
passed_arguments[0] = /usa/folderb
passed_arguments[1] = etc....
Currently I am not having any luck with this so I'm hoping someone could help me with this. Here is some code of what I have working so far:
How I'm trying to copy arguments:
void command_Line()
{
int i = 1;
for(i;parsed_arguments[i]!=NULL;i++)
printf("%s",parsed_arguments[i]);
}
Function to read commands:
void readCommand(char newcommand[]){
printf("readCommand: %s\n", newcommand);
//parsed_arguments = (char* malloc(MAX_ARGS));
// strcpy(newcommand,inputstring);
parsed = parsed_arguments;
*parsed++ = strtok(newcommand,SEPARATORS); // tokenize input
while ((*parsed++ = strtok(NULL,SEPARATORS)))
//printf("test1\n"); // last entry will be NULL
//passed_arguments=parsed_arguments[1];
if(parsed[0]){
char *initial_command =parsed[0];
parsed= parsed_arguments;
while (*parsed) fprintf(stdout,"%s\n ",*parsed++);
// free (parsed);
// free(parsed_arguments);
}//end of if
command_Line();
}//end of ReadCommand
Forking function:
else if(strstr(parsed_arguments[0],"./")!=NULL)
{
int pid;
switch(pid=fork()){
case -1:
printf("Fork error, aborting\n");
abort();
case 0:
execv(parsed_arguments[0],passed_arguments);
}
}
This is what my shell currently outputs. The first time I run it, it outputs something close to what I want, but every subsequent call breaks the program. In addition, each additional call appends the parsed arguments to the output.
This is what the original shell produces. Again it's close to what I want, but not quite. I want to omit the command (i.e. "./testline").
Your testline program is a sensible one to have in your toolbox; I have a similar program that I call al (for Argument List) that prints its arguments, one per line. It doesn't print argv[0] though (I know it is called al). You can easily arrange for your testline to skip argv[0] too. Note that Unix convention is that argv[0] is the name of the program; you should not try to change that (you'll be fighting against the entire system).
#include <stdio.h>
int main(int argc, char **argv)
{
while (*++argv != 0)
puts(*argv);
return 0;
}
Your function command_line() is also reasonable except that it relies unnecessarily on global variables. Think of global variables as a nasty smell (H2S, for example); avoid them when you can. It should be more like:
void command_Line(char *argv[])
{
for (int i = 1; argv[i] != NULL; i++)
printf("<<%s>>\n", argv[i]);
}
If you're stuck with C89, you'll need to declare int i; outside the loop and use just for (i = 1; ...) in the loop control. Note that the printing here separates each argument on a line on its own, and encloses it in marker characters (<< and >> — change to suit your whims and prejudices). It would be fine to skip the newline in the loop (maybe use a space instead), and then add a newline after the loop (putchar('\n');). This makes a better, more nearly general purpose debug routine. (When I write a 'dump' function, I usually use void dump_argv(FILE *fp, const char *tag, char *argv[]) so that I can print to standard error or standard output, and include a tag string to identify where the dump is written.)
Unfortunately, given the fragmentary nature of your readCommand() function, it is not possible to coherently critique it. The commented out lines are enough to elicit concern, but without the actual code you're running, we can't guess what problems or mistakes you're making. As shown, it is equivalent to:
void readCommand(char newcommand[])
{
printf("readCommand: %s\n", newcommand);
parsed = parsed_arguments;
*parsed++ = strtok(newcommand, SEPARATORS);
while ((*parsed++ = strtok(NULL, SEPARATORS)) != 0)
{
if (parsed[0])
{
char *initial_command = parsed[0];
parsed = parsed_arguments;
while (*parsed)
fprintf(stdout, "%s\n ", *parsed++);
}
}
command_Line();
}
The variables parsed and parsed_arguments are both globals and the variable initial_command is set but not used (aka 'pointless'). The if (parsed[0]) test is not safe; you incremented the pointer in the previous line, so it is pointing at indeterminate memory.
Superficially, judging from the screen shots, you are not resetting the parsed_arguments[] and/or passed_arguments[] arrays correctly on the second use; it might be an index that is not being set to zero. Without knowing how the data is allocated, it is hard to know what you might be doing wrong.
I recommend closing this question, going back to your system and producing a minimal SSCCE. It should be under about 100 lines; it need not do the execv() (or fork()), but should print the commands to be executed using a variant of the command_Line() function above. If this answer prevents you deleting (closing) this question, then edit it with your SSCCE code, and notify me with a comment to this answer so I get to see you've done that.

How would I scan phrases from the command line?

I am currently trying to get my program to work the way I want. I am currently at the point where I can open up any text file from the command line (an unlimited amount) and display them. I'd like to expand on this and have users enter phrases that format the displayed text. I have previously posted a similar question and I've gotten some great answers, but I cannot use getopt(). How else would it be possible to scan the command line for a "-w" and a number, so "-w5" and a "-s" with no number. Those are the only two things I'd like to be able to detect. I don't mind if statements, I was hoping for the shortest program in my friends, but at this point, I'd just like to get it done. Any ideas? Multiple if-statements was my friend's idea, I personally think this is unneeded, but if that's what I have to do... If anyone else has any ideas, that would be really useful. I just want my program to detect those two characters from the command line. I'm fairly new to C (I've only made a few programs), but I'm edger to learn and I have tried googling and trying this on my own, but being new to C, trying to find what I need through all the other text and jargon is difficult.
Anything will be useful, thanks.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int l = 1;
while(l != argc)
{
FILE *fp;
fp = fopen(argv[l], "rb");
l++;
if (fp != NULL)
{
int i = 1;
do
{
i = fgetc(fp);
printf("%c",i);
printf(" ");
}
while(i!=-1);
fclose(fp);
}
else
{
printf("Error.\n");
}
}
}
void scanningForWS(int argc, char **argv)
{
}
You should look at plan9's ARGBEGIN and ARGEND macros in their libc.h file (at the very end of the file), to see how it's done (for an example of its usage, see arg(3)).
Alernatively, you can check the suckless implementation of this mechanism, which is very nice (I have re-implemented a version of it which parses arguments even after incorrect flags have been found, but it's not published anywhere. I can publish it if you need that).
The command line arguments are in argv, and since argv is an array, the only way to find a specific element inside of it is to iterate through, checking each element until you get the one you want. If you don't want to write all that yourself, it looks like C has a method called 'lfind' in search.h that does this. Here is an example of how to use it. Hope that helps :3.
Also, the GNU documentation for it

Resources