Sending exec output from function to main method - c

I have a method I call from the main method called that executes ls-l on a certain directory, I want it to execute it and send the result as a string to the main method.
My current flawed code:
char *lsl(){
char *stringts=malloc(1024);
chdir("/Users/file/path");
char * lsargs[] = { "/bin/ls" , "-l", NULL};
stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
return stringts;
}
Currently I am only getting the exec output on the screen, I understand why this is happening(exec getting called before reaching return point). However I don't know how I could possibly do what I want and if it's actually doable.
I was thinking of using pipes and dup2() so I don't let the exec function use stdout but I don't know if it would be possible to put the output in a string.

As Jonathan Leffler already pointed out in comments, there is no '+' operator for concatenating strings in C.
A possibility to dynamically extends strings is to use realloc together with strcat.
For each number of bytes you read from the pipe, you could check the remaining capacity of the originally allocated memory for the string and, if this is not enough, reallocate twice the size.
You have to keep track of the size of the current string yourself. You could do this with a variable of type size_t.
If you combine this with the popen handling, it could look something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *fp;
if ((fp = popen("ls -l", "r")) == NULL) {
perror("popen failed");
return EXIT_FAILURE;
}
size_t str_size = 1024;
char *stringts = malloc(str_size);
if (!stringts) {
perror("stringts allocation failed");
return EXIT_FAILURE;
}
stringts[0] = '\0';
char buf[128];
size_t n;
while ((n = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
buf[n] = '\0';
size_t capacity = str_size - strlen(stringts) - 1;
while (n > capacity) {
str_size *= 2;
stringts = realloc(stringts, str_size);
if (!stringts) {
perror("stringts realloation failed");
return EXIT_FAILURE;
}
capacity = str_size - strlen(stringts) - 1;
}
strcat(stringts, buf);
}
printf("%s\n", stringts);
free(stringts);
if (pclose(fp) != 0) {
perror("pclose failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

You have several flaws in your code:
char *lsl(){
char *stringts=malloc(1024);
chdir("/Users/file/path");
char * lsargs[] = { "/bin/ls" , "-l", NULL};
stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
return stringts;
}
If you malloc(3) a 1024 byte buffer into stringts pointer, but then you assign a different value to the pointer, making your buffer to be lost in the immensity of your RAM.
When you do execv(2) call, all the memory of your process is freed by the kernel and reloaded with an execution of the command ls -l, you'll get the output in the standard output of the process, and then you'll get the prompt of the shell. This makes the rest of your program unuseful, as once you exec, there's no way back, and your program is unloaded and freed.
You can add (+) to a pointer value (you indeed add to the address pointing to the string "The result of the ls -l..." and ---as the result of exec is nothing, as a new program is loaded--- you get nothing) If execv fails, then you get a pointer pointing to the previous char to that string, which is a valid expression in C, but makes your program to behave erratically in an Undefined Behaviour. Use strcpy(3), strcat(3), or snprintf(3), depending on the exact text you want to copy in the space of the buffer you allocated.
Your return an invalid address as a result. The problem here is that, if execv(2) works, it doesn't return. Only if it fails you get an invalid pointer that you cannot use (by the reason above), and of course ls -l has not been executed. Well, you don't say what you got as ouptut, so it is difficult for me to guess if you actually exec()d the program or not.
On other side, you have a popen(3) library function that allows you to execute a subprogram and allows you to read from a file descriptor its output (I recommend you not to chdir gratuitously in your program, as that is a global change in your program environment, IMHO it is better to pass ls(1) the directory you want to list as a parameter)
#include <stdio.h>
FILE *lsl() {
/* the call creates a FILE * descriptor that you can use as input and
* read the output of the ls command. It's bad resources use to try to
* read all in a string and return the string instead. Better read as
* much as you can/need and then pclose() the descriptor. */
return popen("/bin/ls -l /Users/file/path|", "rt");
}
and then you can read (as it can be very long output, you probably don't have enought buffer space to handle it all in memory if you have a huge directory)
FILE *dir = lsl();
if (dir) {
char buffer[1024];
while (fgets(buffer, sizeof buffer, dir)) {
process_line_of_lsl(buffer);
}
pclose(dir); /* you have to use pclose(3) with popen(3) */
}
If you don't want to use popen(3), then you cannot use execv(2) alone, and you have to fork(2) first, to create a new process, and exec() in the child process (after mounting the redirection yourself). Read a good introduction to fork()/exec() and how to redirect I/O between fork() and exec(), as it is far longer and detailed to put it here (again)

Related

How to concat int or pid to string in C the way I like it doing

I have these lines that break and throws error at 439 memcpy(&path[0]+strlen("ls /proc/"),pid,1);
This is the code
void get_pid()
{
char line[1000];
FILE *cmd = popen("pidof a.out", "r");
fgets(line, 100, cmd);
pid_t pid = strtoul(line, NULL, 10);
char *path=malloc(sizeof(char)*100);
memset(path,0,100);
memcpy(path,"ls /proc/",strlen("ls /proc/"));
memcpy(&path[0]+strlen("ls /proc/"),pid,1);
system(path);
free(path);
return;
}
is there any neat way of accomplish I just to execute ls command the way I am trying it just takes /proc/ and concat with pid I got from system(pidof) Actually I need to get into ls /proc/my_pid=pid/fd/ and find socket fd. there is only one socket file in /proc/pid/fd/ directory
How to do it in C
Actually this line is trouble maker
memcpy(&path[0]+strlen("ls /proc/"),pid,1);
I am just taking the address of first character plusing it with strlen and then write with mcmcpy just 1. But obviously the above is wrong since my second parameter to memcpy is type int which is 4 byte and it expect char pointer which is 8 bytes. Can I cast it may be but I need to do it the correct way in C.
It is generally recommended to thing of what you are trying to do and what type are the data.
You first use popen to extract the result of the command pidof a.out. fgets will give you a string ending with a newline. Just replace that last character with a null
...
fgets(line, 100, cmd);
line[strlen(line) -1] = '\0';
You later want to concatenate that value to another string... It is useless to convert it to a pid_t only to convert it back to a string (unless you want to control that the format it correct).
Furthermore, the memxxx functions are recommended to process arbitrary character array that could contain null characters. Here you only handle null terminated strings, so you should use the strxxx functions.
Finally unless you want to experiment with it, using dynamic allocation for a fixed size array is non idiomatic... What you want is:
char path[100] = "ls /proc/";
That is enough to get an array of 100 characters initialized with the content of "ls /proc" followed by null characters.
Just concatenate your initial string:
strcat(path, line);
system(path);
Anyway, this is still poor code, because you should never rely on input data and should always test that what you get is what you expected, but I'll keep that for another answer...
There are a number of ways to go about finding the pid of the current process and then getting a directory listing of the process directory -- but you are making it harder than need be.
Most compiles provide the POSIX function getpid() which will retrieve the current process pid. To determine how many characters are needed for the combined "ls /proc/" and pid, just use the old snprinf() trick with the buffer NULL and the number of chars set to 0 and snprintf() will return the length that would be required to hold the completed string, e.g.
len = snprintf (NULL, 0, "ls /proc/%d", pid); /* determine len req'd */
With the length, you can allocate len + 1 bytes and then use sprintf() to fill the string, e.g.
if (!(path = malloc (len + 1))) { /* allocate len + 1 */
perror ("malloc-path");
return;
}
sprintf (path, "ls /proc/%d", pid); /* create path */
All that remains is making your system() call. Putting it altogether, you can do:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void get_pid ()
{
char *path;
int len;
pid_t pid = getpid(); /* get pid of current proc */
len = snprintf (NULL, 0, "ls /proc/%d", pid); /* determine len req'd */
if (!(path = malloc (len + 1))) { /* allocate len + 1 */
perror ("malloc-path");
return;
}
sprintf (path, "ls /proc/%d", pid); /* create path */
system (path); /* list contents of process directory */
free (path); /* free path */
}
int main () {
get_pid();
}
(note: for your use you can avoid the length checking and dynamic allocations simply be declaring path as a fixed-size array, e.g. char path[128]; would more than suffice, then you can simply call sprintf() and create the desired string)
The version using a fixed-size path simplifies to:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void get_pid ()
{
char path[128]; /* fixed buffer to hold final string */
pid_t pid = getpid(); /* get pid of current proc */
sprintf (path, "ls /proc/%d", pid); /* create path */
system (path); /* list contents of process directory */
}
int main () {
get_pid();
}
Either way is fine.
Example Use/Output
Running the code does provide a listing of the current process directory, e.g.
$ ./bin/lsprocpid
attr coredump_filter fdinfo make-it-fail mountstats oom_score_adj sched stat timerslack_ns
auxv cpuset gid_map map_files net pagemap schedstat statm uid_map
cgroup cwd io maps ns patch_state sessionid status wchan
clear_refs environ latency mem numa_maps personality setgroups syscall
cmdline exe limits mountinfo oom_adj projid_map smaps task
comm fd loginuid mounts oom_score root stack timers
This is probably one of the more concise ways to approach it. There are many ways with strcat(), etc, but when you need to mix numbers and text in a printf() like format-string, then using sprintf() to create the combined string is about as simple way as you have.
Look things over and let me know if you have further questions.

Pipe's write overwrites an allocated space of memory

My program it's pretty big, so I'll highlight the main problem and add some details about it.
First part of my code:
int myPipe[2]; //A global variable, so I don't have to pass it to future functions
int main(int argc, char *args[])
{
mode_t pUmask = umask(0000); //Obsolete variable to my problem
errno = 0; //Obsolete variable to my problem
char pattern[2500] = "Test1"; //Obsolete variable to my problem
int p = 0; //DEFAULT NUMBER OF PROCESSES
int deep = 0; //Obsolete variable to my problem
int n = 1; //Obsolete variable to my problem
if(pipe(myPipe))
{
perror("Pipe Error: ");
exit(-1);
}
if( (write(myPipe[1], &p, (sizeof(int)*3))) == -1) //First write works
{
perror("write: ");
exit(-1);
}
//Then a bunch of code releated to file reading
}
Second part:
{
//in another function
//The part where I create fileName
char* fileName = calloc(strlen(fileData->d_name)+4, sizeof(char));
strcpy(fileName, fileData->d_name);
}
Third part:
//in another another function
if(S_ISREG(data.st_mode))
{
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
printf("\t\tOh boy! It's a regular.\n");
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
if((read(myPipe[0], &p, (sizeof(int)*3))) == -1) //First time I read
{
perror("\t\t read: ");
exit(-1);
}
printf("fileName: %s", fileName); //SEGMENTATION FAULT
There is a bunch of code in between, but it doesn't affect the fileName at all (in fact, up until the "read", fileName was printed flawlessly), and after it a SEGMENTATION FAULT happens.
At one point by changing the printfs locations I was able to get the fileName AFTER the read, which was basically the fileName value("File1") followed by the p integer value(0), which created the new corrupted fileName("File10").
So what's happening? I reserved the space for fileName, I passed the fileName pointer to the following functions up to that read, and supposedly the fd should have it's own adress space as well. HELP.
P.s. if you need more info, I'm willing to give it to you, even the full code, but it's REALLY complicated, and I think I gave you enough proof that fileName doesn't get corrupted at all until the read part, THANK YOU.
P.p.s.
I never close either of the "MyPipe" extremes, since I have to use them multiple times, I wanted to close them at the end of the program.
The statements that write and read the pipe are causing undefined behavior. p is declared:
int p;
But when you write and read it through the pipe, you use sizeof(int)*3, so you're accessing outside the object.
Change those statements to use just sizeof p.

Use mmap to put content into an allocated memory region

I have tried to read documentation on mmap but I am still having a hard time understanding how to use it.
I want to take an argument from the command line and then allocate it to an executable memory region. Then I want to be able to execute from that code.
This is what I have so far:
int main(int argc, char const *argv[]) {
if (argc != 2) {
printf("Correct input was not provided\n");
exit(1);
}
char assembly_code[sizeof argv[1]];
const char *in_value = argv[1];
int x = sscanf(in_value, "%02hhx", assembly_code);
if (x != 1) {
printf("sscanf failed, exited\n");
exit(1);
}
void * map;
size_t ac_size = sizeof(assembly_code) / sizeof(assembly_code[0]);
map = mmap(NULL, ac_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS, -1, 0);
if (map == MAP_FAILED) {
printf("Mapping failed\n");
exit(1);
}
((void (*)(void))map)();
return 0;
}
This is the output/error I am getting: Mapping failed
I don't know if I am using mmap correctly. And if I am I don't believe I am executing it correctly.
For example if this file is run with an argument e8200000004889c64831c048ffc04889c74831d2b2040f054831c0b83c0000004831ff0f05e806000000584883c008c3ebf84869210a it should return Hi! and then terminate. I don't really know how to get this output after the map or how to "call/execute" a mmap.
int x = sscanf(read, "%02hhx", assembly_code);
This only converts a single byte. I don't think there is a standard library function to convert a whole string of hex bytes; you'll have to call sscanf in a loop, incrementing pointers within the input buffer read and the output buffer assembly_code as appropriate.
In your mmap call, if you don't want to map a file, you should use the flag MAP_ANONYMOUS instead of MAP_SHARED. You should also check its return value (it returns MAP_FAILED on error) and report any error. Also, the return value is in principle of type void * instead of int * (though this should make no difference on common Unix systems).
The mmap call (after being fixed) will return a pointer to a block of memory filled with zeros. There is no reason for it to contain your assembly_code, so you'll have to copy it there, perhaps with memcpy. Or you could move your loop and parse the hex bytes directly into the region allocated with mmap.
Your ((void (*)(void))map)(); to transfer control to the mapped address appears to be correct, so once you have the block correctly mapped and populated, it should execute your machine code. I haven't tried to disassemble the hex string you provided to see if it actually would do what you are expecting, but hopefully it does.
Also, read is not a very good name for a variable, since there is also a standard library function by that name. Your code will work, since the local variable shadows the global object, but it would be clearer to choose another name.
Oh, and char assembly_code[sizeof argv[1]]; isn't right. Think carefully about what sizeof does and doesn't do.

Segmentation fault while system() in C

I want to use the "base64" script of linux to encode the data and get it in C.
When I try to compile
char a[200];
strcpy(a, "Hello");
printf("%s", a);
I get the output
Hello
Now whenever I try the code
char a[200];
strcpy(a, system("echo Hello | base64"));
printf("%s", a);
I get the output
aGVsbG8K
Segmentation fault
Even when I remove the "printf" statement, I get the same
aGVsbG8K
Segmentation fault
I want to save the value of the output of
system("echo Hello | base64")
in 'a' and not display it. Please help
If you read the documentation for system you'll discover that it doesn't return a string - it's defined as:
int system(const char *command);
The return value is the return status of the command or -1 if there's an error. You can't get the output using system - the output of the command(s) you run will go straight to stdout.
To get the output from another command you could use something like popen.
FILE *myfile;
char buffer[1024];
myfile=popen("echo Hello | base64","r");
if(myfile)
{
while(fgets(buffer,1024,myfile))
{
printf("%s",buffer);
}
pclose(myfile);
}
Here
strcpy(a, system("echo Hello | base64"));
system() doesn't stores it's result into array a as system() job is to execute the command provided in the argument & print it on console i.e stdout buffer. From the manual page of system
system() executes a command specified in command by calling
/bin/sh -c
command, and returns after the command has been completed.
There is one way to solve the problem i.e instead of printing system() output on stdout you can redirect its output to a file & then read that from file & print. For example
int main(void) {
close(1); /* stdout file descriptor is avilable now */
/* create the file if doesn't exist, if exist truncate the content to 0 length */
int fd = open("data.txt",O_CREAT|O_TRUNC|O_RDWR,0664); /* fd gets assigned with lowest
available fd i.e 1 i.e nowonwards stdout output
gets rediredcted to file */
if(fd == -1) {
/* #TODO error handling */
return 0;
}
system("echo Hello | base64"); /* system output gets stored in file */
int max_char = lseek(fd,0,2);/* make fd to point to end, get the max no of char */
char *a = malloc(max_char + 1); /* to avoid buffer overflow or
underflow, allocate memory only equal to the max no of char in file */
if(a == NULL) {
/* #TODO error handling if malloc fails */
return 0;
}
lseek(fd,0,0);/* from beginning of file */
int ret = read(fd,a,max_char);/* now read out put of system() from
file as array and print it */
if(ret == -1) {
/* #TODO error handling */
return 0;
}
a[ret] = '\0';/* \0 terminated array */
dup2(0,fd);/*fd 0 duplicated to file descriptor where fd points i.e */
printf("output : %s \n", a);
/* to avoid memory leak, free the dynamic memory */
free(a);
return 0;
}
My above suggestion is a temporary fix & I won't recommend this, instead use [popen] as suggested by #chris Turner (http://man7.org/linux/man-pages/man3/popen.3.html) which says
The popen() function opens a process by creating a pipe, forking,
and
invoking the shell. Since a pipe is by definition unidirectional, the
type argument may specify only reading or writing, not both; the
resulting stream is correspondingly read-only or write-only.
For example
int main(void) {
char buf[1024];
FILE *fp = popen("echo Hello | base64","r");
printf("%s\n",fgets(buf,sizeof(buf),fp));
return 0;
}

Process returned -1 (0xFFFFFFFF)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)

Resources