I am writing an application (CLI Based) in C and I want to be able to run a shell script to do system level commands, (its an OSX Specific app). Is there a way to do this?
I tried system() but it says its not valid as of c99.
if (response == 'Y' || response == 'y') {
system("Support/script.sh");
system("Support/deps.sh");
printf("Success");
} else {
printf("Good Bye!\n\n");
}
Check for your current working directory.Looks like te Support folder doesnt exist in the pwd. Mac OS X, an objective-C based, should work with the system calls.
Here is my sample program using popen, if at all you require it. (Just a snippet of my code.. not complete)
char unix_script[1000];
memset(unix_script,'\0',sizeof(unix_script));
snprintf(unix_script,
sizeof(unix_script),
"ksh /usr/mahesh/sessioN.ksh %s %s %s %s %s",
userId,
password,
database,
sbcr_id,
session_id);
char *COMMAND = unix_script,*readLine, *tmp, *commandResult = "";
FILE * fp;
int status;
fp = popen(COMMAND, "w");
if (fp == NULL) {
perror("Command execution failed");
exit(1);
}
//printf("Printing the command output....");
while ((fscanf(fp, "%s", &readLine)) != EOF) {
tmp = (char *) realloc(commandResult, strlen(readLine));
commandResult = tmp;
strcpy(commandResult, readLine);
}
printf("\n output =\n %s\n",commandResult);
status = pclose(fp);
//printf ("Command %s exit status code = %d\n", COMMAND, status);
return status;
Related
I am having some trouble with a basic shell program I am trying to write in c. Whenever I try calling exec in a function such as ls, execvp will return with an error stating that the file or directory could not be found. I think that the problem is with the parsing because in main, the command can be printed but in the function it is blank. Thanks
Here is the code for the function :
int extern_process(char *arg[]){
pid_t pid;
int errnum, ifFail;
printf("i%si\n",arg[0]);
pid = fork();
if(pid == -1){
errnum = errno;
fprintf(stderr,"Error: fork %s", strerror(errnum));
return FAIL;
} else if(pid == 0){
ifFail = execvp(arg[0],arg);
if(ifFail < 0){
errnum = errno;
fprintf(stderr,"Error: exec %s", strerror(errnum));
return FAIL;
}
} else {
pid = wait(NULL);
}
return SUCCESS;
}
Here is the code for the parsing function just in case:
void parse_cmd(char *retval[], char *cmd){
char *tmp;
char a[100];
strcpy(a,cmd);
int i = 0;
tmp = strtok(a," \n\t\0");
if(retval == NULL){
fprintf(stderr, "Error with allocation\n");
return;
}
if(tmp == NULL){
printf("Error with parsing.\n");
return;
}
while(tmp != NULL){
retval[i] = tmp;
tmp = strtok(NULL," \n\t\0");
i++;
}
retval[i] = NULL;
}
Here is the output:
shell> ls
ls
i i
Error: exec no file or directory found
I'm pretty sure strtok returns a pointer that refers to that first argument which, in your case, is a stack allocation. Returning an array of pointers to that stack allocation would result in undefined behavior, I believe. This may or may not be the cause of your problem. It's difficult to know without seeing more of the code. To test, try changing this part of your code like this:
void parse_cmd(char *retval[], char *cmd){
char *tmp;
char *a = strdup(cmd);
int i = 0;
Before using it in production, you need to work out some way to ensure that you free "a" or you'll get a leak. Maybe you could just return it instead of void and free it from elsewhere, or you could actually strdup() each token and write a function to free them all or whatever works for you.
If there are other problems, they may be in other code. I don't really see anything else wrong here.
I am trying to define a global pointer variable that can then truly be set in the main function as seen below. However I am getting a segmentation fault anytime I try to use outputName after this. I know it probably has to do with setting the pointer equal to NULL at the beginning... any help on how I could have a global pointer that is then set in main would be very helpful! Here is the part of my code that is giving me errors:
char* outputName = NULL;
int isNumber(char number[]){
int i;
if (number[0] == '-')
i = 1;
while(number[i] != '\0'){
if (!isdigit(number[i]))
return 0;
i++;
}
return 1;
}
void catcher(int signo){
printf("The program is exiting early");
remove(outputName);
exit(1);
}
int main(int argc, char *argv[]){
if (argc != 4){
fprintf(stderr,"Incorrect number of arguments, must supply three.\n");
exit(1);
}
char* inputName = argv[1];
outputName = argv[2];
signal(SIGINT, catcher);
int result = isNumber(argv[3]);
if (result == 0){
fprintf(stderr, "Invalid maximum line length, please enter an integer\n");
exit(1);
}
int maxChars = (atoi(argv[3])) + 1;
if ((maxChars-1) < 1){
fprintf(stderr, "Invalid third maximum line length, please enter an integer greater than zero\
.\n");
exit(1);
}
FILE* inFile = fopen(inputName, "r");
if (inFile == NULL){
fprintf(stderr, "Error while opening %s.\n", inputName);
exit(1);
}
FILE* outFile = fopen(outputName, "w");
if (outFile == NULL){
fprintf(stderr, "Error while opening %s.\n", outputName);
exit(1);
}
char line[maxChars];
int done = 0;
while (!done){
char *readLine = fgets(line, maxChars, inFile);
if (readLine == NULL){
if (errno == 0){
done = 1;
} else {
fprintf(stderr, "Error when reading line from input file");
exit(1);
}
}
int len = strlen(line);
if (line[len-1] != '\n'){
line[len] = '\n';
line[len+1] = '\0';
char current = ' ';
while (current != '\n')
current = getc(inFile);
}
if (!done){
fputs(line, outFile);
if (errno != 0){
fprintf(stderr, "Error when writing line to output file");
exit(1);
}
}
}
return 0;
}
May be signal handler is getting called prior to outputName getting set to non null value, you can try setting signal handler after outputName = argv[2]; in main()
Read carefully signal(7): since your catcher calls printf which is not an async signal safe function, your code has undefined behavior. Also, your printf control string don't end with \n, and since stdout is line-buffered, no output would be done. Prefer sigaction(2) to signal, and install your signal handler after having assigned outputName.
Global variables used in signal handlers should be declared volatile. So declare your char* volatile outputName; at global scope. Then you might have a test like if (outputName != NULL) remove(outputName); in the handler. A common practice is just to set some volatile sig_atomic_t global flag in the signal handler, and test that flag elsewhere.
And your program is likely to not have time to get any signal. You probably should end your main function with some wait (e.g. read from stdin, or usleep(3), or pause(2), or poll(2)....).
Of course, compile your code with all warnings and debug info (gcc -Wall -g) and use the debugger (gdb); I guess that debugger watchpoints should be very useful to find your bug.
The program you are showing is likely to not exhibit any SEGV. So your actual bug is very probably elsewhere.
Perhaps using strace(1) and/or valgrind could also help.
I have created one function which filters data from a data file and prints it to another file using redirection operator of unix
below is the function
void getdetailbyparam(char *name,char *type,int maxprice,int minprice)
{
printf("NAME:%s\nTYPE:%s\nMAX PRICE:%d MIN PRICE:%d\n",name,type,maxprice,minprice);
char getdetailbyparamfilelocation[1024];
snprintf(getdetailbyparamfilelocation, sizeof(getdetailbyparamfilelocation), "\"%s/getdetailbyparam.txt\"",cwd);
char command[1024];
snprintf(command, sizeof(command),"awk -F['|'] '{if (($3 ~ /.*%s.*/) && ($5==\"%s\") && ($7 >= %d) && ($7 <= %d)) print $7,$3,$1}' OFS=\" | \" %s | sort -n > %s",name,type,minprice,maxprice,databasefilelocation,getdetailbyparamfilelocation);
printf("Command is : %s\n",command);
system(command);
printf("File %s created\n",getdetailbyparamfilelocation);
}
Just need to give paths in "getdetailbyparamfilelocation" and "databasefilelocation".
Now When I call this function the file is created but when I try to open this file after calling the function it is giving me error of "No such file or directory"
Please see the following code
void funct(int sock)
{
char getdetailbyparamfilelocation[1024];
snprintf(getdetailbyparamfilelocation, sizeof(getdetailbyparamfilelocation), "\"%s/getdetailbyparam.txt\"",cwd);
size_t len = 0;
ssize_t read;
FILE *fp;
printf("Start sending data from the file at %s\n",getdetailbyparamfilelocation);
char *line = NULL;
fp = fopen(getdetailbyparamfilelocation, "r");
printf("Reading file \n");
if(fp == NULL)
{
perror("Error");
exit(1);
}
while((read = getline(&line, &len, fp)) != -1)
{
char sendline[1024];
int retu;
snprintf(sendline, sizeof(sendline), line);
printf("SERVER SENDING :%s\n",sendline);
retu = send(sock, line, strlen(line), 0);
}
}
Basically I am coding a client server sytem in which server reads the filtered results and send them to client to displays on client's terminal
Please help and also let me know if any further information is required
You need the double quotes around the file name only if you pass it to the shell. You don't need them when passing the file name to fopen.
Instead of
snprintf(getdetailbyparamfilelocation,
sizeof(getdetailbyparamfilelocation),
"\"%s/getdetailbyparam.txt\"",cwd);
Use
snprintf(getdetailbyparamfilelocation,
sizeof(getdetailbyparamfilelocation),
"%s/getdetailbyparam.txt",cwd);
I am launching pppd using popen in my program to make obtaining the IP address and interface name a little bit easier. My code runs fine independently and is a pretty typical implementation. The problem begins when it runs in the full program (too large to post)... the loop seems to hang for quite a while at the fgets() line. The popen is launched in its own thread that is then managed based on the output.
The popen/pppd code is essentially the following.
int main(void){
pthread_create(&thread, NULL, pppd, (char *)NULL);
pthread_join(thread, NULL);
return 0;
}
void *pppd(char *args){
char* command = malloc(32);
sprintf(command, "pppd %s call %s", dev, provider);
pppd_stream = popen(command, "r");
if(pppd_stream == NULL){
pppd_terminated = TRUE;
return;
}
free(command);
while(fgets(buffer, 128, d->pppd_stream) != NULL){
//handle_output
}
}
CPU usage isnt a problem, the system and the other parts of the program are still responsive and running as expected.
Any thoughts on what could be causing this slow down?
Ensure that your command is null terminated string:
#define COMMAND_BUFFER_SIZE 256 /* Modify this if you need */
snprintf(command, COMMAND_BUFFER_SIZE, "pppd %s call %s", dev, provider);
command[COMMAND_BUFFER_SIZE - 1] = '\0';
pppd_stream = popen(command, "r");
EDIT:
Check your fgets:
while(fgets(buffer, 128, d->pppd_stream) != NULL){
You may want this:
while(fgets(buffer, 128, pppd_stream) != NULL){
I've about got my practice implementation of a Unix shell done, except I'm having an issue with implementing cat when its output is to a file; IE: cat foo.txt > bar.txt - outputting foo's contents to bar.
Let's start from the main function & then I'll define the submethods:
int main(int argc, char **argv)
{
printf("[MYSHELL] $ ");
while (TRUE) {
user_input = getchar();
switch (user_input) {
case EOF:
exit(-1);
case '\n':
printf("[MYSHELL] $ ");
break;
default:
// parse input into cmd_argv - store # commands in cmd_argc
handle_user_input();
//determine input and execute foreground/background process
execute_command();
}
background = 0;
}
printf("\n[MYSHELL] $ ");
return 0;
}
handle_user_input just populates the cmd_argv array to execute the user_input, and removes the > and sets an output flag if the user wishes to output to a file. This is the meat of that method:
while (buffer_pointer != NULL) {
cmd_argv[cmd_argc] = buffer_pointer;
buffer_pointer = strtok(NULL, " ");
if(strcmp(cmd_argv[cmd_argc], ">") == 0){
printf("\nThere was a '>' in %s # index: %d for buffer_pointer: %s \n", *cmd_argv,cmd_argc,buffer_pointer);
cmd_argv[cmd_argc] = strtok(NULL, " ");
output = 1;
}
cmd_argc++;
if(output){
filename = buffer_pointer;
printf("The return of handling input for filename %s = %s + %s \n", buffer_pointer, cmd_argv[0], cmd_argv[1]);
return;
}
}
execute_command is then called, interpreting the now populated cmd_argv. Just to give you an idea of the big picture. Obviously, none of these cases match and the create_process method is called:
int execute_command()
{
if (strcmp("pwd", cmd_argv[0]) == 0){
printf("%s\n",getenv("PATH"));
return 1;
}
else if(strcmp("cd", cmd_argv[0]) == 0){
change_directory();
return 1;
}
else if (strcmp("jobs", cmd_argv[0]) == 0){
display_job_list();
return 1;
}
else if (strcmp("kill", cmd_argv[0]) == 0){
kill_job();
}
else if (strcmp("EOT", cmd_argv[0]) == 0){
exit(1);
}
else if (strcmp("exit", cmd_argv[0]) == 0){
exit(-1);
}
else{
create_process();
return;
}
}
Pretty straight forward, right?
create_process is where I'm having issues.
void create_process()
{
status = 0;
int pid = fork();
background = 0;
if (pid == 0) {
// child process
if(output){
printf("Output set in create process to %d\n",output);
output = 0;
int output_fd = open(filename, O_RDONLY);
printf("Output desc = %d\n",output_fd);
if (output_fd > -1) {
dup2(output_fd, STDOUT_FILENO);
close(output_fd);
} else {
perror("open");
}
}
printf("Executing command, but STDOUT writing to COMMAND PROMPT instead of FILE - as I get the 'open' error above \n");
execvp(*cmd_argv,cmd_argv);
// If an error occurs, print error and exit
fprintf (stderr, "unknown command: %s\n", cmd_argv[0]);
exit(0);
} else {
// parent process, waiting on child process
waitpid(pid, &status, 0);
if (status != 0)
fprintf (stderr, "error: %s exited with status code %d\n", cmd_argv[0], status);
}
return;
}
My printed output_fd = -1, and I manage to get the perror("open") inside the else stating: open: No such file or directory. It then prints that it's "writing to COMMAND PROMPT instead of FILE", as I display to the console. Then executes execvp which handles cat foo.txt, but prints it to the console instead of the file.
I realize it shouldn't at this point, as having output_fd = -1 isnt desirable and should be returning another value; but I cant figure out how to use file descriptors correctly in order to open a new/existing file with cat foo.txt > bar.txt and write to it, as WELL AS GET BACK to the command line's stdin.
I have managed to output to the file, but then lose getting back the correct stdin. Could someone please direct me here? I feel like I'm going in circles over something silly I'm doing wrong or looking over.
Any help is greatly GREATLY appreciated.
Why do you use O_RDONLY if you want to write to the file? My guess is that you should use something like:
int output_fd = open(filename, O_WRONLY|O_CREAT, 0666);
(The 0666 is to set up the access rights when creating).
And obviously, if you can't open a redicted file, you shouldn't launch the command.
First, obvious thing I notice is that you've opened the file O_RDONLY. Not going to work so well for output!
Second, basic process for redirecting the output is:
open file for writing
dup stdout so you can keep a copy if needed. same with stderr if redirecting.
fcntl your duplicate to CLOEXEC (alternatively, use dup3)
dup2 file to stdout
exec the command
and finally, are you really passing around command names as global variables? I think this will come back to haunt you once you try and implement cat foo | ( cat bar; echo hi; cat ) > baz or somesuch.