I'm currently trying to write a program to accept user input to and execute commands in a unix system, the code compiles but when I run it I get a segmentation fault. I think it might be related to the input data type for the system() function but I can't seem to figure it out
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
char argument[1024];
main() {
fgets(argument, 1024, stdin);
strtok (argument, "\n");
char *command = strcat("cd ", argument);
int response = system(command);
if(response == -1)
{
printf("error executing command");
}
}
I apologise if this seems trivial I don't have much experience with c
You are programming in C in an Unix system.
The language C was written just to write Unix itself. system() was written in C, Unix, Windows, Linux, Android, MacOS, Python, java, everything was written in C at first and still is at the most part.
And you have many shells in Unix and derivatives that just run commands as the user types them.
So to use system() to run a command does not add much. Just another level of indirection, an a big security hole, since your program can be used to do unexpected things by not so good people. Using YOUR program.
An alternative
This is the output of the program below
Current directory is: /home/testing/projects/tcursor
directory changed to '/tmp'
Enter name of directory to create: thing
'/tmp/thing' created
Now changing to newly created folder
Current directory is: '/tmp/thing'
The program just
cwd to /tmp
prompt for the name a folder to create
creates the folder
cd to it
shows current dir
returning 1,2,3,4 in case of error, 0 in case of success
So you can see some C code to cd, pwd and mkdir
int main(void)
{
char asw[30];
char buffer[1024];
char* p = buffer;
const char* temp = "/tmp";
p = getcwd(p,1024);
printf("Current directory is: %s\n",p);
int n = chdir(temp);
if ( n != 0 ) return(1);
printf("directory changed to '%s'\n", temp);
printf("Enter name of directory to create: ");
fgets(asw,30,stdin);
asw[strlen(asw)-1] = 0;
n = mkdir(asw, 0777 );
if ( n != 0 ) return(2);
printf("'%s' created\n", buffer);
printf("Now changing to newly created folder\n");
sprintf(buffer,"%s/%s", temp, asw);
n = chdir(buffer);
if ( n != 0 ) return(4);
p = getcwd(p,1024);
printf("Current directory is: '%s'\n",p);
return 0;
Do not use system()
Related
I want to be able to check the owner of a process of which I got the ID from using C on a Unix system. It also needs to work on cygwin. Additionally it would be nice to get the date the process was created, too.
I've seen there are ways through looking up the generated files in /proc/<process-id>/. But unfortunately on cygwin you would need the right permissions to read those files.
If possible I am searching for a way without using those files or system commands. I had also found this threat:
How to programatically get uid from pid in osx using c++?
But it won't work due to missing definitions of KERN_PROC, KERN_PROC_PID and some more.
(Have not found the librarys for those in C)
So in short:
Does anyone know how I could get the informations on a specific process using c without needing system calls or reading the files in /proc/?
here under a simple implementation using ps command.
It's certainly not the most elegant but it should work for Unix and Cygwin:
#include <stdio.h>
#include <string.h>
int get_proc_uid(int pid, char *uid, int uid_size)
{
FILE *fp;
int pid_l, ret = -1;
char uid_l[16];
char cmd[64], line[128];
snprintf(cmd, sizeof(cmd), "ps | grep %d", pid);
fp = popen(cmd, "r");
if(fp == NULL)
return ret;
while(fgets(line, sizeof(line), fp) != NULL)
{
if(strstr(line, "grep") == NULL)//filter grep dummy result
{
sscanf(line, "%d %s", &pid_l, uid_l);
if(pid_l == pid)
{
strncpy(uid, uid_l, uid_size);
ret = 0;
break;
}
}
}
pclose(fp);
return ret;
}
Okay so overall im trying to complete a basic CLI C program which will complete functions such as clear, quit, cd, ls, help (bring up the unix man) etc.. i altered my code and so far i have this, im getting segmination error when trying to execute the cd command part of the program, (im very new to c btw);
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main (int argc, char *argv[])
{
char input[] = " ";
char *argument;
while(strcmp(input, "quit")!= 0)
{
printf("$");
scanf ("%s", input);
if(strcmp(input,"clear") == 0)
{
printf("\e[1;1H\e[2J");
}
else if(strcmp(argv[1],"cd") == 0)
{
if(chdir(argv[2]) == -1)
{
printf("\n directory does not exists");
}
}
else if(strcmp(input, "echo") == 0)
{
char str[50];
scanf("%[^\n]+", str);
printf(" %s", str);
}
}
}
input is declared as a ' ' (space) character. It will never match 'cd'.
This is probably more along the lines of what you want to achieve, where the first parameter is the command (cd), and the second will be the directory:
int main (int argc, char *argv[])
{
char *argument;
if(strcmp(argv[1],"cd") == 0)
{
if(chdir(argv[2]) == -1)
{
printf("\n directory does not exists");
}
}
Edit Also please note that there is no need for the else satement. If chdir does not return an error, it will change the directory, thus no need to call it again in an else.
Additionally, another tip for using system calls in general, it would be of great help if you print the error number returned by the system upon a failure in system call. This will make things easier when things start going wrong. To do this simply include <errno.h>' and modify the printf to printerrno` which gives specific details about the error:
printf("Chdir error: %d", errno);
For instance chdir() does not only return an error when the directory does not exist, but also for example if you do not have permissions to view the contents of the directory. See the man page for a list of possible errors.
To implement your own shell, you need to take input directly from stdin, not from command-line arguments (argv) from another shell. The basic pattern is like this:
Read input
Execute command
Print results
Loop back to step 1
I use linux and c.
First, I soft link bin/zsh to sh
Second, I login as root the run the following program.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *v[3];
if(argc < 2) {
printf("Please type a file name.\n");
return 1;
}
v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = 0;
/* Set q = 0 for system(), and q = 1 for execve */
int q = 0;
if (q == 0){
char *command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
sprintf(command, "%s %s", v[0], v[1]);
system(command);
}
else execve(v[0], v, 0);
return 0 ;
}
Third, I login as a normal user(not root).
Now, I can remove or rewrite a file which I don't have write privilege by using the execute file of this program.
Like this:
./a.out text;\`echo \”Not right\”>text\`”
Now I can write "Not right" into the file "text". I only have read privilege of this file
The read and write privilege of these files.
Fourth, I change q to 1. That means, this time I use execve instead.
And do the same thing as above.
But this time I cannot change the content of the file.
Why?
I google in the internet, but I can not find the different between system and execve.
system invokes a shell to parse the string and handle quoting and variable interpolations and stuff. execve does none of this. It replaces the program with the called program and passes the argument strings exactly as specified; ie. it will not interpret quotes.
You said you did chmod 4755 a.out. That means you're setting the setuid bit and the program will then always run with root privileges, and has write access to text. The string with backquote is passed to the shell which interprets it as a command to write to text.
The reason execve doesn't write to text is that it doesn't interpret its arguments as a shell command and ` doesn't have any special meaning.
I fairly new to the C programming language. I am writing a program that will eventually read through mp3 files from a user inputted directory, and sort the mp3's into artist/album folders by utilizing the metadata in the id3's. I am accessing the user's directory using the system() function call, and generating a .txt file containing all of the mp3's in that directory. However I am running into problems when trying to access the first mp3 file. I am building the mp3 file's path, but the file will not open. The file DOES open when I hard code the path.
#include <stdio.h>
#include <string.h>
struct FILE_head
{
char file_id[3];
char version[2];
char flags;
char size[4];
};
int main()
{
//declare vars
char cd[1200];
char mp3[200];
char dir[1000];
char mp3_path[1200];
FILE *list_file;
FILE *mp3_file;
struct FILE_head id3;
char dir_cmd[1300] = "dir ";
char find_cmd[100] = "/b | find \".mp3\" > \"mp3List.txt\"";
int dir_len;
int amt_read;
//main code
while(1)
{
cd[0]='c';
cd[1]='d';
cd[2]=' ';
cd[3]='\0';
printf("Enter the directory where mp3's are located:");
scanf("%s", dir);
strcat(cd, dir);
if(system(cd) == 0) //if directory is valid, break. otherwise stay in loop/reprompt
break;
printf("Valid directory Ex--> c:\\users\\username\\music\n");
}
//build cmd statement
strcat(dir_cmd, dir);
strcat(dir_cmd, find_cmd);
system(dir_cmd);
dir_len = strlen(dir);
strcpy(mp3_path, dir);
printf("%s\n", mp3_path);
list_file = fopen("mp3List.txt", "rb");
if(list_file != NULL)
{
while(fgets(mp3, sizeof(mp3), list_file))
{
printf("%s", mp3);
strcat(mp3_path, mp3);
printf("%s\n", mp3_path);
mp3_path[strlen(mp3_path)-1] = '\0';
mp3_file = fopen(mp3_path, "rb");
if(mp3_file != NULL)
{
printf("in this loop");
fread(&id3, sizeof(id3), 1, mp3_file);
printf("%s\n", id3.file_id);
}
}
}
return 0;
}
This is my first time posting, so if any more information would be helpful please let me know. I realize there might be "better" ways to access directories, but I don't want to use any functions that are not in the C std lib.
This is my output:
C:\Users\Mitchell\Projects>mp3sort.exe Enter the directory where mp3's
are located:c:\users\mitchell\projects\music_test\
c:\users\mitchell\projects\music_test\ 01 - Time to Pretend.mp3
c:\users\mitchell\projects\music_test\01 - Time to Pretend.mp3
01-all_that_remains-this_calling.mp3
01-all_that_remains-this_calling.mp3t\01 - Time to Pretend.mp3
07 Billy Joel - Everybody Loves You Now.mp3 07 Billy Joel - Everybody
Loves You Now.mp3Time to Pretend.mp3
Tears for the Sheep.mp3 Tears for the Sheep.mp3dy Loves You
Now.mp3Time to Pretend.mp3
C:\Users\Mitchell\Projects>
I know that my current build for the all the files after the first isn't correct, but I was just focused on getting the first mp3_path to work. I removed the newline by: mp3_path[strlen(mp3_path)-1] = '\0';
system() executes provided command in subprocess. When you do system ("cd somedir"), cd somedir is executed in child process, thus working directory of your process remains unaltered.
If you want to change your process working directory, use chdir() (or _chdir(), alternatively SetCurrentDirectory if you want to use Windows API) function.
Alternatively, you can avoid changing working directory by prepending directory to file names.
Here is my code which checks if the file exists :
#include<stdio.h>
#include<zlib.h>
#include<unistd.h>
#include<string.h>
int main(int argc, char *argv[])
{
char *path=NULL;
FILE *file = NULL;
char *fileSeparator = "/";
size_t size=100;
int index ;
printf("\nArgument count is = %d", argc);
if (argc <= 1)
{
printf("\nUsage: ./output filename1 filename2 ...");
printf("\n The program will display human readable information about the PNG file provided");
}
else if (argc > 1)
{
for (index = 1; index < argc;index++)
{
path = getcwd(path, size);
strcat(path, fileSeparator);
printf("\n File name entered is = %s", argv[index]);
strcat(path,argv[index]);
printf("\n The complete path of the file name is = %s", path);
if (access(path, F_OK) != -1)
{
printf("File does exist");
}
else
{
printf("File does not exist");
}
path=NULL;
}
}
return 0;
}
On running the command ./output test.txt test2.txt
The output is:
$ ./output test.txt test2.txt
Argument count is = 3
File name entered is = test.txt
The complete path of the file name is = /home/welcomeuser/test.txt
File does not exist
File name entered is = test2.txt
The complete path of the file name is = /home/welcomeuser/test2.txt
File does not exist
Now test.txt does exist on the system:
$ ls
assignment.c output.exe output.exe.stackdump test.txt
and yet test.txt is shown as a file not existing.
Please help me understand the issue here. Also, please feel free to post any suggestions to improve the code/avoid a bug.
Regards,
darkie
Just because the call to access() fails does not mean that the file does not exist. The call could fail for other reasons.
Use printf("error:%s\n", strerror(errno)); to print out the text of the error message.
Also you are still incorrectly appending to "path" received from getcwd as you were in your previous question. Even though it is not crashing, it is still not correct and could cause you problems... possibly even the problem you have now.
getcwd() allocates a buffer for your path, but that buffer is only sized to fit the path. you are appending to that buffer, going past the end. That's bad, you can't do that. It will cause problems, and occasionally crashes. you need to pause and understand how this getcwd function works and how to properly use it.
I strongly suggest allocating enough room to store the path via malloc() and fpathconf() (hint, PATH_MAX).
A non-standard way of allocating and assembling it would be asprintf().
Just be sure to free the resulting path when its no longer needed, and check every call that could possibly fail due to user typos for failure.
If using malloc(), always check for failure (the result being NULL).
Good luck with your assignment :)