Jack2  1.9.9
JackTools.cpp
1 /*
2  Copyright (C) 2006-2008 Grame
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU Lesser General Public License as published by
6  the Free Software Foundation; either version 2.1 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 */
19 
20 #include "JackConstants.h"
21 #include "JackDriverLoader.h"
22 #include "JackTools.h"
23 #include "JackError.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <signal.h>
28 
29 #ifdef WIN32
30 #include <process.h>
31 #endif
32 
33 
34 using namespace std;
35 
36 namespace Jack {
37 
38  void JackTools::KillServer()
39  {
40  raise(SIGINT);
41  }
42 
43  void JackTools::ThrowJackNetException()
44  {
45  throw JackNetException();
46  }
47 
48  int JackTools::MkDir(const char* path)
49  {
50 #ifdef WIN32
51  return CreateDirectory(path, NULL) == 0;
52 #else
53  return mkdir(path, 0777) != 0;
54 #endif
55  }
56 
57 #define DEFAULT_TMP_DIR "/tmp"
58  char* jack_tmpdir = (char*)DEFAULT_TMP_DIR;
59 
60  int JackTools::GetPID()
61  {
62 #ifdef WIN32
63  return _getpid();
64 #else
65  return getpid();
66 #endif
67  }
68 
69  int JackTools::GetUID()
70  {
71 #ifdef WIN32
72  return _getpid();
73  //#error "No getuid function available"
74 #else
75  return getuid();
76 #endif
77  }
78 
79  const char* JackTools::DefaultServerName()
80  {
81  const char* server_name;
82  if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
83  server_name = JACK_DEFAULT_SERVER_NAME;
84  return server_name;
85  }
86 
87  /* returns the name of the per-user subdirectory of jack_tmpdir */
88 #ifdef WIN32
89 
90  char* JackTools::UserDir()
91  {
92  return "";
93  }
94 
95  char* JackTools::ServerDir(const char* server_name, char* server_dir)
96  {
97  return "";
98  }
99 
100  void JackTools::CleanupFiles(const char* server_name) {}
101 
102  int JackTools::GetTmpdir()
103  {
104  return 0;
105  }
106 
107 #else
108  char* JackTools::UserDir()
109  {
110  static char user_dir[JACK_PATH_MAX + 1] = "";
111 
112  /* format the path name on the first call */
113  if (user_dir[0] == '\0') {
114  if (getenv ("JACK_PROMISCUOUS_SERVER")) {
115  snprintf(user_dir, sizeof(user_dir), "%s/jack", jack_tmpdir);
116  } else {
117  snprintf(user_dir, sizeof(user_dir), "%s/jack-%d", jack_tmpdir, GetUID());
118  }
119  }
120 
121  return user_dir;
122  }
123 
124  /* returns the name of the per-server subdirectory of jack_user_dir() */
125  char* JackTools::ServerDir(const char* server_name, char* server_dir)
126  {
127  /* format the path name into the suppled server_dir char array,
128  * assuming that server_dir is at least as large as JACK_PATH_MAX + 1 */
129 
130  snprintf(server_dir, JACK_PATH_MAX + 1, "%s/%s", UserDir(), server_name);
131  return server_dir;
132  }
133 
134  void JackTools::CleanupFiles(const char* server_name)
135  {
136  DIR* dir;
137  struct dirent *dirent;
138  char dir_name[JACK_PATH_MAX + 1] = "";
139  ServerDir(server_name, dir_name);
140 
141  /* On termination, we remove all files that jackd creates so
142  * subsequent attempts to start jackd will not believe that an
143  * instance is already running. If the server crashes or is
144  * terminated with SIGKILL, this is not possible. So, cleanup
145  * is also attempted when jackd starts.
146  *
147  * There are several tricky issues. First, the previous JACK
148  * server may have run for a different user ID, so its files
149  * may be inaccessible. This is handled by using a separate
150  * JACK_TMP_DIR subdirectory for each user. Second, there may
151  * be other servers running with different names. Each gets
152  * its own subdirectory within the per-user directory. The
153  * current process has already registered as `server_name', so
154  * we know there is no other server actively using that name.
155  */
156 
157  /* nothing to do if the server directory does not exist */
158  if ((dir = opendir(dir_name)) == NULL) {
159  return;
160  }
161 
162  /* unlink all the files in this directory, they are mine */
163  while ((dirent = readdir(dir)) != NULL) {
164 
165  char fullpath[JACK_PATH_MAX + 1];
166 
167  if ((strcmp(dirent->d_name, ".") == 0) || (strcmp (dirent->d_name, "..") == 0)) {
168  continue;
169  }
170 
171  snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_name, dirent->d_name);
172 
173  if (unlink(fullpath)) {
174  jack_error("cannot unlink `%s' (%s)", fullpath, strerror(errno));
175  }
176  }
177 
178  closedir(dir);
179 
180  /* now, delete the per-server subdirectory, itself */
181  if (rmdir(dir_name)) {
182  jack_error("cannot remove `%s' (%s)", dir_name, strerror(errno));
183  }
184 
185  /* finally, delete the per-user subdirectory, if empty */
186  if (rmdir(UserDir())) {
187  if (errno != ENOTEMPTY) {
188  jack_error("cannot remove `%s' (%s)", UserDir(), strerror(errno));
189  }
190  }
191  }
192 
193  int JackTools::GetTmpdir()
194  {
195  FILE* in;
196  size_t len;
197  char buf[JACK_PATH_MAX + 2]; /* allow tmpdir to live anywhere, plus newline, plus null */
198 
199  if ((in = popen("jackd -l", "r")) == NULL) {
200  return -1;
201  }
202 
203  if (fgets(buf, sizeof(buf), in) == NULL) {
204  pclose(in);
205  return -1;
206  }
207 
208  len = strlen(buf);
209 
210  if (buf[len - 1] != '\n') {
211  /* didn't get a whole line */
212  pclose(in);
213  return -1;
214  }
215 
216  jack_tmpdir = (char *)malloc(len);
217  memcpy(jack_tmpdir, buf, len - 1);
218  jack_tmpdir[len - 1] = '\0';
219 
220  pclose(in);
221  return 0;
222  }
223 #endif
224 
225  void JackTools::RewriteName(const char* name, char* new_name)
226  {
227  size_t i;
228  for (i = 0; i < strlen(name); i++) {
229  if ((name[i] == '/') || (name[i] == '\\'))
230  new_name[i] = '_';
231  else
232  new_name[i] = name[i];
233  }
234  new_name[i] = '\0';
235  }
236 
237 #ifdef WIN32
238 
239 void BuildClientPath(char* path_to_so, int path_len, const char* so_name)
240 {
241  snprintf(path_to_so, path_len, ADDON_DIR "/%s.dll", so_name);
242 }
243 
244 void PrintLoadError(const char* so_name)
245 {
246  // Retrieve the system error message for the last-error code
247  LPVOID lpMsgBuf;
248  LPVOID lpDisplayBuf;
249  DWORD dw = GetLastError();
250 
251  FormatMessage(
252  FORMAT_MESSAGE_ALLOCATE_BUFFER |
253  FORMAT_MESSAGE_FROM_SYSTEM |
254  FORMAT_MESSAGE_IGNORE_INSERTS,
255  NULL,
256  dw,
257  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
258  (LPTSTR) &lpMsgBuf,
259  0, NULL );
260 
261  // Display the error message and exit the process
262  lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
263  (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)so_name) + 40) * sizeof(TCHAR));
264  _snprintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
265  TEXT("error loading %s err = %s"), so_name, lpMsgBuf);
266 
267  jack_error((LPCTSTR)lpDisplayBuf);
268 
269  LocalFree(lpMsgBuf);
270  LocalFree(lpDisplayBuf);
271 }
272 
273 #else
274 
275 void PrintLoadError(const char* so_name)
276 {
277  jack_log("error loading %s err = %s", so_name, dlerror());
278 }
279 
280 void BuildClientPath(char* path_to_so, int path_len, const char* so_name)
281 {
282  const char* internal_dir;
283  if ((internal_dir = getenv("JACK_INTERNAL_DIR")) == 0) {
284  if ((internal_dir = getenv("JACK_DRIVER_DIR")) == 0) {
285  internal_dir = ADDON_DIR;
286  }
287  }
288 
289  snprintf(path_to_so, path_len, "%s/%s.so", internal_dir, so_name);
290 }
291 
292 #endif
293 
294 
295 } // end of namespace
296 
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107