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