diff --git a/common/JackServerLaunch.cpp b/common/JackServerLaunch.cpp new file mode 100644 index 00000000..5b392656 --- /dev/null +++ b/common/JackServerLaunch.cpp @@ -0,0 +1,189 @@ +/* +Copyright (C) 2001-2003 Paul Davis +Copyright (C) 2004-2006 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackChannel.h" +#include "JackLibGlobals.h" +#include "JackServerLaunch.h" + +using namespace Jack; + +#ifndef WIN32 + +#ifdef __APPLE__ +#define JACK_LOCATION "/usr/local/bin" +#define JACK_DEFAULT_DRIVER "coreaudio" +#endif + +#ifdef __linux__ +#define JACK_LOCATION "/usr/local/bin" +#define JACK_DEFAULT_DRIVER "alsa" +#endif + +/* Exec the JACK server in this process. Does not return. */ +static void start_server_aux(const char* server_name) +{ + FILE* fp = 0; + char filename[255]; + char arguments[255]; + char buffer[255]; + char* command = 0; + size_t pos = 0; + size_t result = 0; + char** argv = 0; + int i = 0; + int good = 0; + int ret; + + snprintf(filename, 255, "%s/.jackdmprc", getenv("HOME")); + fp = fopen(filename, "r"); + + if (!fp) { + fp = fopen("/etc/jackdmprc", "r"); + } + /* if still not found, check old config name for backwards compatability */ + if (!fp) { + fp = fopen("/etc/jackdmp.conf", "r"); + } + + if (fp) { + arguments[0] = '\0'; + ret = fscanf(fp, "%s", buffer); + while (ret != 0 && ret != EOF) { + strcat(arguments, buffer); + strcat(arguments, " "); + ret = fscanf(fp, "%s", buffer); + } + if (strlen(arguments) > 0) { + good = 1; + } + } + + if (!good) { + command = JACK_LOCATION "/jackdmp"; + strncpy(arguments, JACK_LOCATION "/jackdmp -T -d "JACK_DEFAULT_DRIVER, 255); + } else { + result = strcspn(arguments, " "); + command = (char*)malloc(result+1); + strncpy(command, arguments, result); + command[result] = '\0'; + } + + argv = (char**)malloc(255); + + while (1) { + /* insert -T and -nserver_name in front of arguments */ + if (i == 1) { + argv[i] = (char*)malloc(strlen ("-T") + 1); + strcpy (argv[i++], "-T"); + if (server_name) { + size_t optlen = strlen("-n"); + char* buf = (char*)malloc(optlen + strlen(server_name) + 1); + strcpy(buf, "-n"); + strcpy(buf+optlen, server_name); + argv[i++] = buf; + } + } + + result = strcspn(arguments + pos, " "); + if (result == 0) { + break; + } + argv[i] = (char*)malloc(result + 1); + strncpy(argv[i], arguments+pos, result); + argv[i][result] = '\0'; + pos += result + 1; + ++i; + } + argv[i] = 0; + execv(command, argv); + + /* If execv() succeeds, it does not return. There's no point + * in calling jack_error() here in the child process. */ + fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno)); +} + +static int start_server(const char* server_name, jack_options_t options) +{ + if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) { + return 1; + } + + /* The double fork() forces the server to become a child of + * init, which will always clean up zombie process state on + * termination. This even works in cases where the server + * terminates but this client does not. + * + * Since fork() is usually implemented using copy-on-write + * virtual memory tricks, the overhead of the second fork() is + * probably relatively small. + */ + switch (fork()) { + case 0: /* child process */ + switch (fork()) { + case 0: /* grandchild process */ + start_server_aux(server_name); + _exit(99); /* exec failed */ + case -1: + _exit(98); + default: + _exit(0); + } + case -1: /* fork() error */ + return 1; /* failed to start server */ + } + + /* only the original parent process goes here */ + return 0; /* (probably) successful */ +} + +int server_connect(char* name) +{ + JackClientChannelInterface* channel = JackGlobals::MakeClientChannel(); + int res = channel->ServerCheck(name); + delete channel; + return res; +} + +int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status) +{ + if (server_connect(va->server_name) < 0) { + int trys; + if (start_server(va->server_name, options)) { + int my_status1 = *status | JackFailure | JackServerFailed; + *status = (jack_status_t)my_status1; + return -1; + } + trys = 5; + do { + sleep(1); + if (--trys < 0) { + int my_status1 = *status | JackFailure | JackServerFailed; + *status = (jack_status_t)my_status1; + return -1; + } + } while (server_connect(va->server_name) < 0); + int my_status1 = *status | JackServerStarted; + *status = (jack_status_t)my_status1; + } + + return 0; +} + +#endif diff --git a/common/JackServerLaunch.h b/common/JackServerLaunch.h new file mode 100644 index 00000000..1938b7ec --- /dev/null +++ b/common/JackServerLaunch.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 2001-2003 Paul Davis +Copyright (C) 2004-2006 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackServerLaunch__ +#define __JackServerLaunch__ + +#include "varargs.h" +#include "types.h" + +int server_connect(char* name); +int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status); + +#endif