Jack2  1.9.7
JackTools.cpp
00001 /*
00002   Copyright (C) 2006-2008 Grame
00003 
00004   This program is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU Lesser General Public License as published by
00006   the Free Software Foundation; either version 2.1 of the License, or
00007   (at your option) any later version.
00008 
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU Lesser General Public License for more details.
00013 
00014   You should have received a copy of the GNU Lesser General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018 */
00019 
00020 #include "JackConstants.h"
00021 #include "JackDriverLoader.h"
00022 #include "JackTools.h"
00023 #include "JackError.h"
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <assert.h>
00027 
00028 #ifdef WIN32
00029 #include <process.h>
00030 #endif
00031 
00032 
00033 using namespace std;
00034 
00035 namespace Jack {
00036 
00037     void JackTools::KillServer()
00038     {
00039 #ifdef WIN32
00040         exit(1);
00041 #else
00042         kill(GetPID(), SIGINT);
00043 #endif
00044     }
00045 
00046     void JackTools::ThrowJackNetException() 
00047     {
00048         throw JackNetException();
00049     }
00050     
00051      int JackTools::MkDir(const char* path)
00052      {
00053 #ifdef WIN32
00054         return CreateDirectory(path, NULL) == 0;
00055 #else
00056         return mkdir(path, 0777) != 0;
00057 #endif
00058     }
00059 
00060 #define DEFAULT_TMP_DIR "/tmp"
00061     char* jack_tmpdir = (char*)DEFAULT_TMP_DIR;
00062 
00063     int JackTools::GetPID()
00064     {
00065 #ifdef WIN32
00066         return _getpid();
00067 #else
00068         return getpid();
00069 #endif
00070     }
00071 
00072     int JackTools::GetUID()
00073     {
00074 #ifdef WIN32
00075         return  _getpid();
00076         //#error "No getuid function available"
00077 #else
00078         return getuid();
00079 #endif
00080     }
00081 
00082     const char* JackTools::DefaultServerName()
00083     {
00084         const char* server_name;
00085         if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
00086             server_name = JACK_DEFAULT_SERVER_NAME;
00087         return server_name;
00088     }
00089 
00090     /* returns the name of the per-user subdirectory of jack_tmpdir */
00091 #ifdef WIN32
00092 
00093     char* JackTools::UserDir()
00094     {
00095         return "";
00096     }
00097 
00098     char* JackTools::ServerDir(const char* server_name, char* server_dir)
00099     {
00100         return "";
00101     }
00102 
00103     void JackTools::CleanupFiles(const char* server_name) {}
00104 
00105     int JackTools::GetTmpdir()
00106     {
00107         return 0;
00108     }
00109 
00110 #else
00111     char* JackTools::UserDir()
00112     {
00113         static char user_dir[JACK_PATH_MAX + 1] = "";
00114 
00115         /* format the path name on the first call */
00116         if (user_dir[0] == '\0') {
00117             if (getenv ("JACK_PROMISCUOUS_SERVER")) {
00118                 snprintf(user_dir, sizeof(user_dir), "%s/jack", jack_tmpdir);
00119             } else {
00120                 snprintf(user_dir, sizeof(user_dir), "%s/jack-%d", jack_tmpdir, GetUID());
00121             }
00122         }
00123 
00124         return user_dir;
00125     }
00126 
00127     /* returns the name of the per-server subdirectory of jack_user_dir() */
00128     char* JackTools::ServerDir(const char* server_name, char* server_dir)
00129     {
00130         /* format the path name into the suppled server_dir char array,
00131         * assuming that server_dir is at least as large as JACK_PATH_MAX + 1 */
00132 
00133         snprintf(server_dir, JACK_PATH_MAX + 1, "%s/%s", UserDir(), server_name);
00134         return server_dir;
00135     }
00136 
00137     void JackTools::CleanupFiles(const char* server_name)
00138     {
00139         DIR* dir;
00140         struct dirent *dirent;
00141         char dir_name[JACK_PATH_MAX + 1] = "";
00142         ServerDir(server_name, dir_name);
00143 
00144         /* On termination, we remove all files that jackd creates so
00145         * subsequent attempts to start jackd will not believe that an
00146         * instance is already running. If the server crashes or is
00147         * terminated with SIGKILL, this is not possible. So, cleanup
00148         * is also attempted when jackd starts.
00149         *
00150         * There are several tricky issues. First, the previous JACK
00151         * server may have run for a different user ID, so its files
00152         * may be inaccessible. This is handled by using a separate
00153         * JACK_TMP_DIR subdirectory for each user. Second, there may
00154         * be other servers running with different names. Each gets
00155         * its own subdirectory within the per-user directory. The
00156         * current process has already registered as `server_name', so
00157         * we know there is no other server actively using that name.
00158         */
00159 
00160         /* nothing to do if the server directory does not exist */
00161         if ((dir = opendir(dir_name)) == NULL) {
00162             return;
00163         }
00164 
00165         /* unlink all the files in this directory, they are mine */
00166         while ((dirent = readdir(dir)) != NULL) {
00167 
00168             char fullpath[JACK_PATH_MAX + 1];
00169 
00170             if ((strcmp(dirent->d_name, ".") == 0) || (strcmp (dirent->d_name, "..") == 0)) {
00171                 continue;
00172             }
00173 
00174             snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_name, dirent->d_name);
00175 
00176             if (unlink(fullpath)) {
00177                 jack_error("cannot unlink `%s' (%s)", fullpath, strerror(errno));
00178             }
00179         }
00180 
00181         closedir(dir);
00182 
00183         /* now, delete the per-server subdirectory, itself */
00184         if (rmdir(dir_name)) {
00185             jack_error("cannot remove `%s' (%s)", dir_name, strerror(errno));
00186         }
00187 
00188         /* finally, delete the per-user subdirectory, if empty */
00189         if (rmdir(UserDir())) {
00190             if (errno != ENOTEMPTY) {
00191                 jack_error("cannot remove `%s' (%s)", UserDir(), strerror(errno));
00192             }
00193         }
00194     }
00195 
00196     int JackTools::GetTmpdir()
00197     {
00198         FILE* in;
00199         size_t len;
00200         char buf[JACK_PATH_MAX + 2]; /* allow tmpdir to live anywhere, plus newline, plus null */
00201 
00202         if ((in = popen("jackd -l", "r")) == NULL) {
00203             return -1;
00204         }
00205 
00206         if (fgets(buf, sizeof(buf), in) == NULL) {
00207             pclose(in);
00208             return -1;
00209         }
00210 
00211         len = strlen(buf);
00212 
00213         if (buf[len - 1] != '\n') {
00214             /* didn't get a whole line */
00215             pclose(in);
00216             return -1;
00217         }
00218 
00219         jack_tmpdir = (char *)malloc(len);
00220         memcpy(jack_tmpdir, buf, len - 1);
00221         jack_tmpdir[len - 1] = '\0';
00222 
00223         pclose(in);
00224         return 0;
00225     }
00226 #endif
00227 
00228     void JackTools::RewriteName(const char* name, char* new_name)
00229     {
00230         size_t i;
00231         for (i = 0; i < strlen(name); i++) {
00232             if ((name[i] == '/') || (name[i] == '\\'))
00233                 new_name[i] = '_';
00234             else
00235                 new_name[i] = name[i];
00236         }
00237         new_name[i] = '\0';
00238     }
00239 
00240 #ifdef WIN32
00241 
00242 void BuildClientPath(char* path_to_so, int path_len, const char* so_name)
00243 {
00244     snprintf(path_to_so, path_len, ADDON_DIR "/%s.dll", so_name);
00245 }
00246 
00247 void PrintLoadError(const char* so_name)
00248 {
00249     // Retrieve the system error message for the last-error code
00250     LPVOID lpMsgBuf;
00251     LPVOID lpDisplayBuf;
00252     DWORD dw = GetLastError();
00253 
00254     FormatMessage(
00255         FORMAT_MESSAGE_ALLOCATE_BUFFER |
00256         FORMAT_MESSAGE_FROM_SYSTEM |
00257         FORMAT_MESSAGE_IGNORE_INSERTS,
00258         NULL,
00259         dw,
00260         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00261         (LPTSTR) &lpMsgBuf,
00262         0, NULL );
00263 
00264     // Display the error message and exit the process
00265     lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
00266         (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)so_name) + 40) * sizeof(TCHAR));
00267     _snprintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
00268         TEXT("error loading %s err = %s"), so_name, lpMsgBuf);
00269 
00270     jack_error((LPCTSTR)lpDisplayBuf);
00271 
00272     LocalFree(lpMsgBuf);
00273     LocalFree(lpDisplayBuf);
00274 }
00275 
00276 #else
00277 
00278 void PrintLoadError(const char* so_name)
00279 {
00280     jack_log("error loading %s err = %s", so_name, dlerror());
00281 }
00282 
00283 void BuildClientPath(char* path_to_so, int path_len, const char* so_name)
00284 {
00285     const char* internal_dir;
00286     if ((internal_dir = getenv("JACK_INTERNAL_DIR")) == 0) {
00287         if ((internal_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00288             internal_dir = ADDON_DIR;
00289         }
00290     }
00291 
00292     snprintf(path_to_so, path_len, "%s/%s.so", internal_dir, so_name);
00293 }
00294 
00295 #endif
00296 
00297 }  // end of namespace
00298