Unix based OS: Coding Bug - c

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

Related

How to make a print.exe which you can access through the cmd and takes parameters in c [duplicate]

This question already has answers here:
How to print argv arguments from main function in C?
(7 answers)
Closed 2 years ago.
I have this c program right here:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
int main(int argc, char* argv[]) {
int i;
int forparam = sizeof(argv);
if (argc > 1) {
for (i = 1; i < forparam; i++) {
if (i == 1) {
printf("%s", argv[i]);
}
if (i > 1) {
printf(" %s", argv[i]);
}
}
}
else {
printf("One argument expected\n");
}
}
You type the name of the file in the Win10 cmd and a parameter and it prints out the parameter onto the cmd. At least that's what it's supposed to do. It can't take up more than 3 parameters and if you enter 1 or 2 parameters then it prints them out but with a "(null)" in the end. How can I make it to work? Because a space indicates another parameter it ignores it that's why I need all this code. Your help would be immensely appreciated!
sizeof(argv) gives you the size in bytes of the argv pointer object, not the number of elements it points to.
argc gives you the number of parameters on the command line, where argv[0] is the command used to invoke the program:
int main( int argc, char **argv )
{
printf( "Command used to invoke program: %s\n", argv[0] );
for ( int i = 1; i < argc; i++ )
printf( "parameter %d: %s\n", i, argv[i] );
}
You don't need forparam, you have everything you need with argc:
int main(int argc, char* argv[]) {
if (argc > 1) {
int i;
for (i = 1; i < argc; i++) {
if (i == 1) {
printf("%s", argv[i]);
} else if (i > 1) {
printf(" %s", argv[i]);
}
}
return EXIT_SUCCESS;
} else {
printf("One argument expected\n");
return EXIT_FAILURE;
}
}
Moreover, sizeof argv returns the size of the pointer argv, not the number of elements in argv (which is not known to the compiler).
Notice that sizeof(argv) is computed at compile-time, and is maybe 4 (bytes) or probably 8 (bytes). I suppose it is 8.
Then your for loop is executed with i=1, then with i=2 up to i=7
You probably want for (i = 1; i < argc; i++)
Read Modern C and see this C reference for more.
Take inspiration from the C source code of existing free software, in particular GNU coreutils.

Vigenere cs50 doesn't complain when lacks second arg

I don't understand why it isn't working. It complains when there are 3 or more args but not when there is only the one Vigenere arg. I have looked at other people who had same problem and they said this worked to resolve.....not sure what I am missing here. When I run ./vigenere, I get a segmentation fault. It works normally with 2 arg like ./vigenere bard and complains when extra arguments are given like ./vigenere bard dfads.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc,string argv[])
{
string sKeyWord = argv[1];
int iKeyLength = strlen(sKeyWord);
int iKey[iKeyLength];
string sPlainText = "";
int counter = 0;
int iAccept = 0;
do
{
if(argc != 2) // <-----this should work whats wrong?
{
printf("Invalid argument! Please enter program name and keyword.\n");
return 1;
}
else if(argv[1])
{
for(int i = 0; i < iKeyLength; i++)
{
if (!isalpha(argv[1][i]))
{
printf("Invalid entry, please use letters only.\n");
return 1;
}
else
{
iAccept = 1;
}
}
}
}while(iAccept == 0);
for(int i = 0; i < iKeyLength; i++)
{
iKey[i] = toupper(sKeyWord[i]) - 65;
}
sPlainText = GetString();
int iPlainText = strlen(sPlainText);
for(int j = 0; j < iPlainText; j++)
{
if(!isalpha(sPlainText[j]))
{
printf("%c",sPlainText[j]);
counter++;
}
if(islower(sPlainText[j]))
{
printf("%c",((((sPlainText[j] - 97) + iKey[(j - counter)%iKeyLength])%26)+ 97));
}
if(isupper(sPlainText[j]))
{
printf("%c",((((sPlainText[j] - 65) + iKey[(j - counter)%iKeyLength])%26)+ 65));
}
}
printf("\n");
return 0;
}
I'd rewrite the top, argument handling section of your program like this.
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s key\n", argv[0]);
return 1;
}
char *sKeyWord = argv[1];
int iKeyLength = strlen(sKeyWord);
int iKey[iKeyLength];
for (int i = 0; i < iKeyLength; i++)
{
if (!isalpha(sKeyword[i]))
{
fprintf(stderr, "%s: Invalid character '%c' in key; please use letters only.\n",
argv[0], sKeyword[i]);
return 1;
}
iKey[i] = toupper(sKeyWord[i]) - 'A';
}
…your code to read the text to be enciphered and encipher it, etc…
The key point is to check that there is an argv[1] before trying to do anything with it. I eliminated a do { … } while (…); loop because the argument isn't going to change on a second iteration. That allows the iAccept variable to be eliminated. Note that errors are reported on standard error, not standard output. Also notice that the messages are preceded by the program name (argv[0]). A 'Usage' message is often the best way to report a problem; it's a simple reminder to those who run the program what's required. Note too that the error message for the alphabetic check reports the erroneous character; that helps people see what the program thinks is wrong.
This is more or less what the comments were suggesting should be done.
I've not reviewed the enciphering code; there could be undiagnosed problems in that too. There are many related questions on SO that would provide you with answers to any such problems, though.

C - Function that executes a command

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.

Access violation reading location 0x00000000. with argv[]

I am running the following program and got errors:
First-chance exception at 0x0f32d440 (msvcr100d.dll) in c.exe: 0xC0000005: Access violation reading location 0x00000000.
Unhandled exception at 0x772815de in c.exe: 0xC0000005: Access violation reading location 0x00000000.
The program '[9048] c.exe: Native' has exited with code -1073741510 (0xc000013a).
Here is the code
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[], char *env[]) //char *argv[]
{
int i;
printf("These are the %d command- line arguments passed to main:\n\n", argc);
if(strcmp(argv[1],"123")==0)
{
printf("success\n");
}
else
for(i=0; i<=argc; i++)
//if(strcmp(argv[1],"abc")==0)
printf("argv[%d]:%s\n", i, argv[i]);
/*printf("\nThe environment string(s)on this system are:\n\n");
for(i=0; env[i]!=NULL; i++)
printf(" env[%d]:%s\n", i, env[i]);*/
system("pause");
}
The problem should be with the strcmp function but I dont know how to solve it.
Could anyone help?
You have (at least) two problems.
The first is doing this:
if(strcmp(argv[1],"123")==0)
without first checking that argc >= 2.
The second is this:
for(i=0; i<=argc; i++)
in that you should be processing arguments 0 thru argc - 1 inclusive. What that loop does is process arguments 0 through argc and argv[argc] is always NULL.
The following program illustrates one way to fix this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]) {
int i;
printf ("These are the %d command-line argument(s) passed to main:\n", argc);
if ((argc >= 2) && (strcmp (argv[1], "123") == 0)) {
printf (" success\n");
} else {
for (i = 0; i < argc; i++) {
printf (" argv[%d] = [%s]\n", i, argv[i]);
}
}
return 0;
}
You can see that the comparison with "123" is only done after ensuring that argv[1] is populated correctly. In addition, the loop has been changed to exclude argv[argc] since that's not one of the arguments. A transcript follows:
pax> testprog
These are the 1 command-line argument(s) passed to main:
argv[0] = [testprog]
pax> testprog 123
These are the 2 command-line argument(s) passed to main:
success
pax> testprog a b c
These are the 4 command-line argument(s) passed to main:
argv[0] = [testprog]
argv[1] = [a]
argv[2] = [b]
argv[3] = [c]
for(i=0; i<=argc; i++) should be for(i=0; i<argc; i++).
C/C++ arrays are 0 to n-1. You are running 1 spot off the end of the array.

passing value of array to the start of the loop

My goal is to have the user view the history of entered commands (historyArray - done) and allow him to re-run any command in history, by entering history 1, history 2 where 1 and 2 is the number of the list of commands as printed-out from historyArray.
I have managed to obtain the index from the second parameter (history 1) of the user input. My question is now, how to execute that specific command obtained from history N?
So, for example:
hshell> test [Enter]
Command not found
hshell> history 1
Command not found
Here is my progress:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[])
{
int i=0; int j=0; int k=0;
int elementCounter = 0;
char inputString[100];
char *result=NULL;
char delims[] = " ";
char historyArray[30][20] = {0};
char tokenArray[20][20] ;
int tempIndex = 0;
char hCommand[2][20]={0};
do
{
j = 0;
printf("hshell>");
gets(inputString);
strcpy (historyArray[k], inputString);
k = (k+1) % 20;
if (elementCounter <= 20)
{
elementCounter++;
}
if (elementCounter == 21)
{
k = 20;
for (i=0; i<20; i++)
{
strcpy(historyArray[i], historyArray[i+1]);
}
strcpy (historyArray[19], inputString);
}
// Break the string into parts
result = strtok(inputString, delims);
while (result!=NULL)
{
strcpy(tokenArray[j], result);
j++;
result= strtok(NULL, delims);
}
if (strcmp(tokenArray[0], "exit") == 0)
{
return 0;
}
else if (strcmp(tokenArray[0], "history") == 0)
{
if (j>1)
{
tempIndex = atoi(tokenArray[1]);
strcpy(hCommand,historyArray[tempIndex-1]);
puts(hCommand);
// tempIndex = atoi(tokenArray[j]);
//puts(tempIndex);
}
else
{
//print history array
for (i=0; i<elementCounter-1;i++)
printf("%i. %s\n", i+1, historyArray[i]);
}
}
else
{
printf("Command not found\n");
}
}while (1);
}
hCommand is where I store the command as obtained from historyArray.
I am using a Windows machine.
After getting the name of the command you wanna execute I would suggest going through the system call exec. Take into account the exec replaces the current process image with the one you are going to execute. Otherwise you might be interested in fork.
EDIT#1 Then I believe you need this API. Note that I am not familiar which of those functions are equivalent to the ones I have provided in first place. With a bit time you could figure it out, right? :)
You can use the 'system' function in stdlib.h.
#include <stdlib.h>
int system(const char *command);
This function is included in both windows and *nix. You do not need to worry about calling fork or CreateProcess separately, this will take care of it for you. See the MSDN documentation for details.
In your code, you would write:
system(hCommand);
It will return when the command finishes (it is a synchronous call).

Resources