How do I open a file in its default program - Linux - c

How do I programmatically open a file in its default program in Linux (im using Ubuntu 10.10).
For example, opening *.mp3 will open the file in Movie Player (or something else).

You need to run gnome-open, kde-open, or exo-open, depending on which desktop you are using.
I believe there is a project called xdg-utils that attempts to provide a unified interface to the local desktop.
So, something like:
snprintf(s, sizeof s, "%s %s", "xdg-open", the_file);
system(s);
Beware of code injection. It's safer to bypass scripting layers with user input, so consider something like:
pid = fork();
if (pid == 0) {
execl("/usr/bin/xdg-open", "xdg-open", the_file, (char *)0);
exit(1);
}
// parent will usually wait for child here

Ubuntu 10.10 is based on GNOME. So, it would be good idea to use
g_app_info_launch_default_for_uri().
Something like this should work.
#include <stdio.h>
#include <gio/gio.h>
int main(int argc, char *argv[])
{
gboolean ret;
GError *error = NULL;
g_type_init();
ret = g_app_info_launch_default_for_uri("file:///etc/passwd",
NULL,
&error);
if (ret)
g_message("worked");
else
g_message("nop: %s", error->message);
return 0;
}
BTW, xdg-open, a shell script, tries to determin your desktop environment and call a known helper like gvfs-open for GNOME, kde-open for KDE, or something else. gvfs-open ends up calling g_app_info_launch_default_for_uri().

A simple solution with less coding:
I've tested this program on my Ubuntu and it is working fine, and if I am not wrong you are looking for something like this
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("firefox file:///dox/song.mp3");
return 0;
}

Related

make a program to run other program on C

I have a program that works like this
program1.exe program2.exe
I need to make it run like this
%USERPROFILE%\program1.exe program2.exe
How can that be done on C?
From what I could see, you're using Microsoft Windows.
There are (at least) two answers to your question, a simple one, and one tied to the Windows operating system interface, usually called Win32 API.
Let's use the simple one. If your prefer to have more control about the execution of the 2nd program, please comment.
#include <stdio.h> /* printf() */
#include <stdlib.h> /* system() */
int main(int argc, char* const* argv)
{
int rv;
if (argc < 2) {
printf("Please inform the name of the program to execute.\n");
return 1;
}
rv = system(argv[1]);
printf("Program execution returned %d\n", rv);
return 0;
}

How can I use chdir function in Linux?

I have a question, here is my original code in the testchdir.c file:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
if (argc < 2)
{
printf("Usage: %s <pathname\n",argv[0]);
exit(1);
}
if (chdir(argv[1]) == 0)
{
printf("success in chdir\n");
return 0;
}
else
{
printf("error happened");
exit(1);
}
}
In my Linux system, my original path is /home/Tom3543, then when I compile my codes above using gcc -o testchdir testchdir.c, it looks good. Later on, I want to change my path and execute the program, so I type
./testchdir /home/tom3543/C++
"success in chdir" appeared in my terminal, but my path is still /home/Tom3543 in my terminal. Can someone help me explain why? I am confused about that!
It's because the shell starts a new process for your program, and you only change the current directory in that new process. The shells process will be unaffected.
Unfortunately (for you) there's no real good (or legal) way to change the working directory of the parent process (the process of the shell).

Better way to discard output from function tested by glib test

If i test functions with glib's testharness, I always face the ugly fact, that the output of the functions I'm testign is mixed with the output of glib's functions.
This code:
#include <stdlib.h>
#include <glib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
void to_test(void)
{
printf("this function is being tested");
}
void test_to_test(void)
{
to_test();
}
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/test", test_to_test);
return g_test_run();
}
generates:
/test: this function is being testedOK
The only solution I found was redirecting the filedescriptors of standardout/-err to /dev/null for the time the function is called and resetting them afterwards, like:
void test_to_test(void)
{
int backup, new;
new = open("/dev/null", O_WRONLY);
backup = dup(STDOUT_FILENO);
dup2(new, STDOUT_FILENO);
to_test();
fflush(stdout);
close(new);
dup2(backup, STDOUT_FILENO);
}
The output looks as intended:
/test: OK
Unfortunately this approach is 1.) ugly and 2.) POSIX specific. So my question is: Is there any other way to do this, so that the code is portable and at the same time aestetically appealing?
Thanks in advance!
Yours in neverending, beautiful, transcendetal love
floxo
This is possible using freopen and/or fdopen. There isn't a cross platform way of doing this unfortunately, luckily Windows has an fdopen equivalent which you can use (Is there a Windows equivalent to fdopen for HANDLEs?).
Note that this will only work if using stdio. It won't work if for some reason something is writing directly to the fd
As a longer term recommendation, why not use fprintf instead? and maintain a FILE* field in your structure which can be directed to custom output or wherever.

How to create a process on Mac OS using fork() and exec()

I am working on a relatively simple, independent "process starter" that I would like to get to work on Windows (XP, Vista, 7), Linux (Ubuntu 10.10) and especially Mac OS X (10.6). Linux and Windows basically work, but I'm having some trouble with the Mac version.
I was hoping fork() and exec() functions would work the same way under Mac OS as they work in Linux. So my first question is:
Should I use these to create a
process on the Mac or are there any
platform specific functions to be
used?
My current code (which worked fine under Linux) to debug this looks something like this:
pid_t processId = 0;
if (processId = fork()) == 0)
{
const char * tmpApplication = "/Path/to/TestApplication";
int argc = 1;
char * argv[argc + 1];
argv[0] = tmpApplication;
argv[1] = NULL;
execv(tmpApplication, argv);
}else
{
//[...]
}
Any idea if this could work under Mac OS X as well, because my child process is simply not being launched, while there are no errors that would come up.
Thank you!
The following program, adapted from your code, works just fine for me under OS X:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main (void) {
pid_t processId;
if ((processId = fork()) == 0) {
char app[] = "/bin/echo";
char * const argv[] = { app, "success", NULL };
if (execv(app, argv) < 0) {
perror("execv error");
}
} else if (processId < 0) {
perror("fork error");
} else {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
I suggest you start with this simple fragment, and if it works keep adding things until you find what makes it break.
Is TestApplication an actual executable, or an application bundle (.app)? You can only launch actual executables using functions like execv(). Usually the executable inside an application bundle can be found at ApplicationName.app/Contents/MacOS/ApplicationName.

Programmatically retrieving the absolute path of an OS X command-line app

On Linux, an application can easily get its absolute path by querying /proc/self/exe. On FreeBSD, it's more involved, since you have to build up a sysctl call:
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[1024];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
but it's still completely doable. Yet I cannot find a way to determine this on OS X for a command-line application. If you're running from within an app bundle, you can determine it by running [[NSBundle mainBundle] bundlePath], but because command-line applications are not in bundles, this doesn't help.
(Note: consulting argv[0] is not a reasonable answer, since, if launched from a symlink, argv[0] will be that symlink--not the ultimate path to the executable called. argv[0] can also lie if a dumb application uses an exec() call and forget to initialize argv properly, which I have seen in the wild.)
The function _NSGetExecutablePath will return a full path to the executable (GUI or not). The path may contain symbolic links, "..", etc. but the realpath function can be used to clean those up if needed. See man 3 dyld for more information.
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0)
printf("executable path is %s\n", path);
else
printf("buffer too small; need size %u\n", size);
The secret to this function is that the Darwin kernel puts the executable path on the process stack immediately after the envp array when it creates the process. The dynamic link editor dyld grabs this on initialization and keeps a pointer to it. This function uses that pointer.
I believe there is much more elegant solution, which actually works for any PID, and also returns the absolute path directly:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libproc.h>
int main (int argc, char* argv[])
{
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid();
ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
if ( ret <= 0 ) {
fprintf(stderr, "PID %d: proc_pidpath ();\n", pid);
fprintf(stderr, " %s\n", strerror(errno));
} else {
printf("proc %d: %s\n", pid, pathbuf);
}
return 0;
}
Looks like the answer is that you can't do it:
I'm trying to achieve something like
lsof's functionality and gather a
whole bunch of statistics and info
about running processes. If lsof
weren't so slow, I'd be happy sticking
with it.
If you reimplement lsof, you will find
that it's slow because it's doing a
lot of work.
I guess that's not really because lsof
is user-mode, it's more that it has to
scan through a task's address space
looking for things backed by an
external pager. Is there any quicker
way of doing this when I'm in the
kernel?
No. lsof is not stupid; it's doing
what it has to do. If you just want a
subset of its functionality, you might
want to consider starting with the
lsof source (which is available) and
trimming it down to meet your
requirements.
Out of curiosity, is p_textvp used at
all? It looks like it's set to the
parent's p_textvp in kern_fork (and
then getting released??) but it's not
getting touched in any of kern_exec's
routines.
p_textvp is not used. In Darwin, the
proc is not the root of the address
space; the task is. There is no
concept of "the vnode" for a task's
address space, as it is not
necessarily initially populated by
mapping one.
If exec were to populate p_textvp, it
would pander to the assumption that
all processes are backed by a vnode.
Then programmers would assume that it
was possible to get a path to the
vnode, and from there it is a short
jump to the assumption that the
current path to the vnode is the path
from which it was launched, and that
text processing on the string might
lead to the application bundle name...
all of which would be impossible to
guarantee without substantial penalty.
—Mike Smith, Darwin Drivers
mailing list
This is late, but [[NSBundle mainBundle] executablePath] works just fine for non-bundled, command-line programs.
There is no guaranteed way I think.
If argv[0] is a symlink then you could use readlink().
If command is executed through the $PATH then one could
try some of: search(getenv("PATH")), getenv("_"), dladdr()
Why not simply realpath(argv[0], actualpath);? True, realpath has some limits (documented in the manual page) but it handles symbolic links fine. Tested on FreeBSD and Linux
% ls -l foobar
lrwxr-xr-x 1 bortzmeyer bortzmeyer 22 Apr 29 07:39 foobar -> /tmp/get-real-name-exe
% ./foobar
My real path: /tmp/get-real-name-exe
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <sys/stat.h>
int
main(argc, argv)
int argc;
char **argv;
{
char actualpath[PATH_MAX + 1];
if (argc > 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(1);
}
realpath(argv[0], actualpath);
fprintf(stdout, "My real path: %s\n", actualpath);
exit(0);
}
If the program is launched via PATH, see pixelbeat's solution.
http://developer.apple.com/documentation/Carbon/Reference/Process_Manager/Reference/reference.html#//apple_ref/c/func/GetProcessBundleLocation
GetProcessBundleLocation seems to work.

Resources