JackServerLaunch.cpp

00001 /*
00002 Copyright (C) 2001-2003 Paul Davis
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU Lesser General Public License as published by
00007 the Free Software Foundation; either version 2.1 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public License
00016 along with this program; if not, write to the Free Software 
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 
00019 */
00020 
00021 #ifndef ADDON_DIR
00022 #include "config.h"
00023 #endif
00024 
00025 #include "JackChannel.h"
00026 #include "JackLibGlobals.h"
00027 #include "JackServerLaunch.h"
00028 
00029 using namespace Jack;
00030 
00031 #ifndef WIN32
00032 
00033 /* Exec the JACK server in this process.  Does not return. */
00034 static void start_server_aux(const char* server_name)
00035 {
00036         FILE* fp = 0;
00037         char filename[255];
00038         char arguments[255];
00039         char buffer[255];
00040         char* command = 0;
00041         size_t pos = 0;
00042         size_t result = 0;
00043         char** argv = 0;
00044         int i = 0;
00045         int good = 0;
00046         int ret;
00047         
00048         snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
00049         fp = fopen(filename, "r");
00050 
00051         if (!fp) {
00052                 fp = fopen("/etc/jackdrc", "r");
00053         }
00054         /* if still not found, check old config name for backwards compatability */
00055         if (!fp) {
00056                 fp = fopen("/etc/jackd.conf", "r");
00057         }
00058 
00059         if (fp) {
00060                 arguments[0] = '\0';
00061                 ret = fscanf(fp, "%s", buffer);
00062                 while (ret != 0 && ret != EOF) {
00063                         strcat(arguments, buffer);
00064                         strcat(arguments, " ");
00065                         ret = fscanf(fp, "%s", buffer);
00066                 }
00067                 if (strlen(arguments) > 0) {
00068                         good = 1;
00069                 }
00070                 fclose(fp);
00071         }
00072 
00073         if (!good) {
00074                 command = (char*)(JACK_LOCATION "/jackd");
00075                 strncpy(arguments, JACK_LOCATION "/jackd -T -d "JACK_DEFAULT_DRIVER, 255);
00076         } else {
00077                 result = strcspn(arguments, " ");
00078                 command = (char*)malloc(result + 1);
00079                 strncpy(command, arguments, result);
00080                 command[result] = '\0';
00081         }
00082 
00083         argv = (char**)malloc(255);
00084   
00085         while (1) {
00086                 /* insert -T and -nserver_name in front of arguments */
00087                 if (i == 1) {
00088                         argv[i] = (char*)malloc(strlen ("-T") + 1);
00089                         strcpy (argv[i++], "-T"); 
00090                         if (server_name) {
00091                                 size_t optlen = strlen("-n");
00092                                 char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
00093                                 strcpy(buf, "-n");
00094                                 strcpy(buf + optlen, server_name);
00095                                 argv[i++] = buf;
00096                         }
00097                 }
00098 
00099                 result = strcspn(arguments + pos, " ");
00100                 if (result == 0) {
00101                         break;
00102                 }
00103                 argv[i] = (char*)malloc(result + 1);
00104                 strncpy(argv[i], arguments + pos, result);
00105                 argv[i][result] = '\0';
00106                 pos += result + 1;
00107                 ++i;
00108         }
00109         argv[i] = 0;
00110         execv(command, argv);
00111 
00112         /* If execv() succeeds, it does not return. There's no point
00113          * in calling jack_error() here in the child process. */
00114         fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
00115 }
00116 
00117 static int start_server(const char* server_name, jack_options_t options)
00118 {
00119         if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
00120                 return 1;
00121         }
00122 
00123         /* The double fork() forces the server to become a child of
00124          * init, which will always clean up zombie process state on
00125          * termination. This even works in cases where the server
00126          * terminates but this client does not.
00127          *
00128          * Since fork() is usually implemented using copy-on-write
00129          * virtual memory tricks, the overhead of the second fork() is
00130          * probably relatively small.
00131          */
00132         switch (fork()) {
00133                 case 0:                                 /* child process */
00134                         switch (fork()) {
00135                                 case 0:                 /* grandchild process */
00136                                         start_server_aux(server_name);
00137                                         _exit(99);      /* exec failed */
00138                                 case -1:
00139                                         _exit(98);
00140                                 default:
00141                                         _exit(0);
00142                         }
00143                 case -1:                        /* fork() error */
00144                         return 1;               /* failed to start server */
00145         }
00146 
00147         /* only the original parent process goes here */
00148         return 0;                       /* (probably) successful */
00149 }
00150 
00151 int server_connect(char* server_name)
00152 {
00153         JackClientChannelInterface* channel = JackGlobals::MakeClientChannel();
00154         int res = channel->ServerCheck(server_name);
00155         channel->Close();
00156         delete channel;
00157         return res;
00158 }
00159 
00160 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
00161 {
00162         if (server_connect(va->server_name) < 0) {
00163                 int trys;
00164                 if (start_server(va->server_name, options)) {
00165                         int my_status1 = *status | JackFailure | JackServerFailed;
00166                         *status = (jack_status_t)my_status1;
00167                         return -1;
00168                 }
00169                 trys = 5;
00170                 do {
00171                         sleep(1);
00172                         if (--trys < 0) {
00173                                 int my_status1 = *status | JackFailure | JackServerFailed;
00174                                 *status = (jack_status_t)my_status1;
00175                                 return -1;
00176                         }
00177                 } while (server_connect(va->server_name) < 0);
00178                 int my_status1 = *status | JackServerStarted;
00179                 *status = (jack_status_t)my_status1;
00180         }
00181         
00182         return 0;
00183 }
00184 
00185 #endif

Generated on Thu Feb 14 11:16:02 2008 for Jackdmp by  doxygen 1.5.1