Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have searched around but can't find an answer to my problem.
I am cross compiling a C++ application for the beagle bone black and wish to use the linux system() function as follows :
system("echo DM-GPIO-Test > $SLOTS");
It is to add a device overlay to control GPIO pins. The echo command "echo DM-GPIO-Test > $SLOTS" works fine when executed directly on the terminal on the beagle bone from anywhere. SLOTS is an environmental variable I defined and DM-GPIO-Test-00A0.dtb0 is in /lib/firmware
I get the following error on execution of the c++ application however:
"sh: 1: cannot create : Directory nonexistent"
Is it incorrect to call the system function like I did ?
Thanks in advance
system("echo DM-GPIO-Test > $SLOTS");
This smells bad and should be avoided.
What you probably want is to write a string in a file given by your SLOTS environment variable (see environ(7)). For that particular use, you don't need to fork any /bin/sh process (which is what system(3) does). You could simply fetch that environment variable using getenv(3).
So you might try:
const char*slotspath = getenv("SLOTS");
if (!slotspath) {
fprintf(stderr, "no SLOTS\n");
exit(EXIT_FAILURE);
}
FILE* fslots = fopen(slotspath, "w");
if (!fslots) { perror(slotspath); exit(EXIT_FAILURE); };
fputs("DM-GPIO-Test\n", fslots);
fclose(fslots), fslots = NULL;
Be aware that the environment of your program -assuming it is started by some other utility (or from init or systemd)- is probably different (and smaller) than your interactive environment.
Perhaps your slotspath should not come from your environment, but from some configuration file under /etc/ (that your program should parse), or some program argument.
So I suggest to define the format of some configuration file and parse it, and get your slotspath from it.
No, it doesn't display anything doing system("echo $SLOTS")
In this case the environment variable SLOTS is simply unset/empty in the environment used by your application. Depending on your use case you either need to set it before you start the binary, or using setenv(), or replacing it directly in the string you pass to system(). If you expect the variable to be set in any of the user's profile settings you need to be aware of the different behaviour of your shell (e. g. bash) at invocation, and place it in the right file, or create a wrapper script that sets it.
$ cat .profile
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
[...]
A good idea would also be to check it for valid values in your application prior to the system() call, using getenv() to obtain it and asserting if it doesn't match the requirements.
Be aware that it is best practice to enclose shell variables containing strings into double quotes, in case they contain spaces, and the identifier into curly brackets, to avoid ambiguities:
system("echo DM-GPIO-Test > \"${SLOTS}\"");
And as Basile points out in a separate answer, avoiding invocation of the shell and handling the logic of writing the file completely in C would even be more powerful regarding the handling of errors and special cases, but also results in more code (which could contain bugs of its own...).
Related
My very simple C program just hangs and I don’t know why.
I am trying to make a simple executable to handle multiple monotonous actions for me every time I start a new programming session.
So I decided with something simple (below) yet every time I run it, the app just hangs, never returns. So I have to Ctrl-C out of it. I have added printf commands to see if it goes anywhere, but those never appear.
My build command returns no error messages:
gcc -o tail tail.c
Just curious what I am missing.
#include <stdio.h>
#include <unistd.h>
int main() {
chdir("\\var\\www");
return 0;
}
There are at least two problems with the source code:
It is unlikely that you have a sub-directory called \var\www in your current directory — Ubuntu uses / and not \ for path separators.
Even if there was a sub-directory with the right name, your program would change directory to it but that wouldn't affect the calling program.
You should check the return value from chdir() — at minimum:
if (chdir("/var/www") != 0)
{
perror("chdir");
exit(EXIT_FAILURE);
}
And, as Max pointed out, calling your program by the name of a well-known utility such as tail is likely to lead to confusion. Use a different name.
Incidentally, don't use test as a program name either. That, too, will lead to confusion as it is a shell built-in as well as an executable in either /bin or /usr/bin. There is also a program /bin/cd or /usr/bin/cd on your machine — it will check that it can change directory, but won't affect the current directory of your shell. You have to invoke it explicitly by the full pathname to get it to run at all because cd is another shell built-in.
Two things:
First, that's not what Linux paths look like
Second, check the return value from chdir()
ie
if (chdir("/var/www") != 0)
printf("failed to change directory");
Finally, the effect of chdir() lasts for the duration of the program. It will not change the current directory of your shell once this program finishes.
The other answers adequately cover the issues in your C code. However, the reason you are seeing it hang is because you chose the name tail for your program.
In Linux, tail is a command in /usr/bin in most setups, and if you just type tail at the command line, the shell searches the $PATH first, and runs this. Without any parameters, it waits for input on its stdin. You can end it by pressing control-d to mark the end of file.
You can bypass the $PATH lookup by typing ./tail instead.
$ tail
[system tail]
$ ./tail
[tail in your current directory]
It is a good idea to use ./ as a habit, but you can also avoid confusion by not naming your program the same as common commands. Another name to avoid is test which is a shell built-in for testing various aspects of files, but appears to do nothing as it reports results in its system return code.
I always use the -x (or debug flag) when it come to bash script, or shell scripts in general.
Now i'm curious to know, is there an equivalent, either using a specific compiler options, (i use gcc, but i don't mind any other compilers) or by using a specific code in my project?
Basically i just wanted a way to emulate what bash does (using the debug flag) which show which command/function was launched first, in order, and also show the output of said function, with additional errors message etc.But for C.
I'm aware of most debug option out there, especially considering the compiler, but i really wish i could do this in my C projects too.(especially the part where it show what is executed in order, like bash does with -x)
NB: There isn't any goal in this specific question beside the question itself, as i'm just curious if this exist, and thus don't have any need for it beside the actual knowledge acquired from said answered question.
Yes, you can mimic this behaviour with a debugger.
With GDB for instance you can write "Init Files" and "Command Files" in which you can write a simple loop:
break main
run
while 1
next
end
If you put a file named .gdbinit in the directory where you start gdb, this file will be executed or gdb will lead you on the way to configure it in order that it will be executed.
The other option is to pipe this file into your gdb-call:
gdb a.out < debug_me_like-x
Where the "debug_me_like-x" file is the one mentioned above.
As a reference for the "Command Files" have a look here.
I am having trouble with the function fopen(). I would always send the exact location of a file as an arguement to fopen(),
which would look something like this:
fopen("c:\\Users/Username/Desktop/Projects/program_name/version 1.0/data/important_data.txt", "r");
That works just fine on my computer, but what if I decide to transfer the program to another computer?
The location would completely change.
It would no longer be:
c:\\Users/Username/Desktop/Projects/program_name/version 1.0/data/important_data.txt
But it would rather be something like:
c:\\Users/OtherUsername/Desktop/program_name/version 1.0/data/important_data.txt
My question is, how do I make a portable function which can obtain the location of a file, if I only give the
name (including the type e.g. .txt) of the file to the function?
Keep in mind, I've been learning C for less than a year. There are still a lot of things which I must learn, and
things like this are of high importance.
this is operating system specific. on linux you can use the locate shell command and parse its output ( http://www.linfo.org/locate.html )
C: Run a System Command and Get Output?
How do I execute a Shell built-in command with a C function?
however this solution will only work on linux. i think yano's solution in the comments above is better ...
I am new in linux.I have problem in accessing my defined environment varibales in C program.
I have defined one variable in linux command terminal as follows:
$ ExampleVar="Hi"
And in C program I am trying to access it using
getenv("ExampleVar")
But it is null every time. When I try to access other environment variables like USER, getenv gives correct results. I have also tried extern collection of unistd.h
It is not showing ExampleVar too.
Please help me.
It depends upon your shell. If you use bash -see bash(1) for more- type
export EXAMPLEVAR="Hi"
in the shell (e.g. in the terminal before running your program), then use getenv("EXAMPLEVAR") in your C program. See getenv(3)
If you don't export a bash variable foo, you still can use $foo in your bash commands, but getenv("foo") would fail and return NULL from inside compiled C programs.
Conventionally, environment variables have full capital names. See environ(7)
See also env(1) command.
I've been following tutorials online on C coding, and the code is using the Apache APR library.
It uses the apr_proc_t structure to execute an external app.
I'm confused about this function, could someone explain what this function means:
apr_status_t apr_procattr_cmdtype_set ( apr_procattr_t * attr,
apr_cmdtype_e cmd
)
Set what type of command the child process will call.
Parameters:
attr The procattr we care about.
cmd The type of command. One of:
APR_SHELLCMD -- Anything that the shell can handle
APR_PROGRAM -- Executable program (default)
APR_PROGRAM_ENV -- Executable program, copy environment
APR_PROGRAM_PATH -- Executable program on PATH, copy env
The apr_procattr_cmdtype_set function is used to tell APR how you want to execute the external command, it probably just sets an internal flag and does a bit of bookkeeping.
Let us look at the enum apr_cmdtype_e:
APR_SHELLCMD
use the shell to invoke the program
APR_PROGRAM
invoke the program directly, no copied env
APR_PROGRAM_ENV
invoke the program, replicating our environment
APR_PROGRAM_PATH
find program on PATH, use our environment
APR_SHELLCMD_ENV
use the shell to invoke the program, replicating our environment
The first and last options (APR_SHELLCMD and APR_SHELLCMD_ENV) pretty much say "use a portable version of system" (with or without copying the current environment variables to the new process). The others are just variations on the Unix fork/exec pair with the flag choosing which of the exec family of functions to use.