]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
wxLogStderr sends output to debugger too under Windows
[wxWidgets.git] / src / unix / utilsunx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utilsunx.cpp
3 // Purpose: generic Unix implementation of many wx functions
4 // Author: Vadim Zeitlin
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #include "wx/defs.h"
19 #include "wx/string.h"
20
21 #include "wx/intl.h"
22 #include "wx/log.h"
23
24 #include "wx/utils.h"
25 #include "wx/process.h"
26
27 #include "wx/unix/execute.h"
28
29 #include <stdarg.h>
30 #include <dirent.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <sys/wait.h>
36 #include <pwd.h>
37 #include <errno.h>
38 #include <netdb.h>
39 #include <signal.h>
40 #include <fcntl.h> // for O_WRONLY and friends
41 #include <time.h> // nanosleep() and/or usleep()
42
43 #ifdef HAVE_UNAME
44 #include <sys/utsname.h> // for uname()
45 #endif // HAVE_UNAME
46
47 // ----------------------------------------------------------------------------
48 // conditional compilation
49 // ----------------------------------------------------------------------------
50
51 // many versions of Unices have this function, but it is not defined in system
52 // headers - please add your system here if it is the case for your OS.
53 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
54 #if (defined(__SUN__) && !defined(__SunOs_5_6) && \
55 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
56 defined(__osf__)
57 extern "C"
58 {
59 void usleep(unsigned long usec);
60 };
61 #endif // Unices without usleep()
62
63 // many versions of Unices have this function, but it is not defined in system
64 // headers - please add your system here if it is the case for your OS.
65 // SunOS (and Solaris) and DG-UX are like this.
66 #if defined(__SOLARIS__) || defined(__osf__)
67 extern "C"
68 {
69 pid_t wait4(pid_t pid, int *statusp, int options,
70 struct rusage *rusage);
71 }
72
73 #define wxWait4(pid, stat, flags, rusage) wait4(pid, stat, flags, rusage)
74 #elif defined(__sgi) || defined(__HPUX__)
75 // no wait4() at all on these systems
76 // TODO verify whether wait3() really works in this situation
77 #define wxWait4(pid, stat, flags, rusage) wait3(stat, flags, rusage)
78 #else
79 // other Unices: assume have wait4(), although it's not standard (but
80 // Linux and FreeBSD do have it)
81 #define wxWait4(pid, stat, flags, rusage) wait4(pid, stat, flags, rusage)
82 #endif // wait4()
83
84 // ============================================================================
85 // implementation
86 // ============================================================================
87
88 // ----------------------------------------------------------------------------
89 // sleeping
90 // ----------------------------------------------------------------------------
91
92 void wxSleep(int nSecs)
93 {
94 sleep(nSecs);
95 }
96
97 void wxUsleep(unsigned long milliseconds)
98 {
99 #if defined(HAVE_NANOSLEEP)
100 timespec tmReq;
101 tmReq.tv_sec = milliseconds / 1000;
102 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
103
104 // we're not interested in remaining time nor in return value
105 (void)nanosleep(&tmReq, (timespec *)NULL);
106 #elif defined(HAVE_USLEEP)
107 // uncomment this if you feel brave or if you are sure that your version
108 // of Solaris has a safe usleep() function but please notice that usleep()
109 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
110 // documented as MT-Safe
111 #if defined(__SUN__) && defined(wxUSE_THREADS)
112 #error "usleep() cannot be used in MT programs under Solaris."
113 #endif // Sun
114
115 usleep(milliseconds * 1000); // usleep(3) wants microseconds
116 #else // !sleep function
117 #error "usleep() or nanosleep() function required for wxUsleep"
118 #endif // sleep function
119 }
120
121 // ----------------------------------------------------------------------------
122 // process management
123 // ----------------------------------------------------------------------------
124
125 int wxKill(long pid, int sig)
126 {
127 return kill(pid, sig);
128 }
129
130 long wxExecute( const wxString& command, bool sync, wxProcess *process )
131 {
132 static const char *IFS = " \t\n";
133
134 wxCHECK_MSG( !command.IsEmpty(), 0, "can't exec empty command" );
135
136 int argc = 0;
137 char *argv[127];
138 char *tmp = new char[command.Len() + 1];
139 strcpy(tmp, command);
140
141 argv[argc++] = strtok(tmp, IFS);
142 while ((argv[argc++] = strtok((char *) NULL, IFS)) != NULL)
143 /* loop */ ;
144
145 long lRc = wxExecute(argv, sync, process);
146
147 delete [] tmp;
148
149 return lRc;
150 }
151
152 bool wxShell(const wxString& command)
153 {
154 wxString cmd;
155 if ( !!command )
156 cmd.Printf("xterm -e %s", command.c_str());
157 else
158 cmd = command;
159
160 return wxExecute(cmd) != 0;
161 }
162
163 void wxHandleProcessTermination(wxEndProcessData *proc_data)
164 {
165 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
166
167 int status = 0;
168 wxWait4(pid, &status, 0, (rusage *) NULL);
169
170 if (proc_data->process)
171 proc_data->process->OnTerminate(proc_data->pid, status);
172
173 if (proc_data->pid > 0)
174 {
175 delete proc_data;
176 }
177 else
178 {
179 // wxExecute() will know about it
180 proc_data->exitcode = status;
181
182 proc_data->pid = 0;
183 }
184 }
185
186 long wxExecute( char **argv, bool sync, wxProcess *process )
187 {
188 wxCHECK_MSG( *argv, 0, "can't exec empty command" );
189
190 int end_proc_detect[2];
191
192 // create pipes
193 if (pipe(end_proc_detect) == -1)
194 {
195 wxLogSysError( _("Pipe creation failed") );
196 return 0;
197 }
198
199 // fork the process
200 #ifdef HAVE_VFORK
201 pid_t pid = vfork();
202 #else
203 pid_t pid = fork();
204 #endif
205 if (pid == -1)
206 {
207 wxLogSysError( _("Fork failed") );
208 return 0;
209 }
210 else if (pid == 0)
211 {
212 // we're in child
213 close(end_proc_detect[0]); // close reading side
214
215 // These three lines close the open file descriptors to to avoid any
216 // input/output which might block the process or irritate the user. If
217 // one wants proper IO for the subprocess, the "right thing to do is
218 // to start an xterm executing it.
219 if (sync == 0)
220 {
221 // leave stderr opened, it won't do any hurm
222 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
223 {
224 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
225 close(fd);
226 }
227 }
228
229 #if 0
230 close(STDERR_FILENO);
231
232 // some programs complain about stderr not being open, so redirect
233 // them:
234 open("/dev/null", O_RDONLY); // stdin
235 open("/dev/null", O_WRONLY); // stdout
236 open("/dev/null", O_WRONLY); // stderr
237 #endif
238
239 #ifdef _AIX
240 execvp ((const char *)*argv, (const char **)argv);
241 #else
242 execvp (*argv, argv);
243 #endif
244
245 // there is no return after successful exec()
246 fprintf(stderr, _("Can't execute '%s'\n"), *argv);
247
248 _exit(-1);
249 }
250 else
251 {
252 // we're in parent
253 close(end_proc_detect[1]); // close writing side
254
255 wxEndProcessData *data = new wxEndProcessData;
256 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
257
258 if ( sync )
259 {
260 wxASSERT_MSG( !process, "wxProcess param ignored for sync exec" );
261 data->process = NULL;
262
263 // sync execution: indicate it by negating the pid
264 data->pid = -pid;
265
266 // it will be set to 0 from GTK_EndProcessDetector
267 while (data->pid != 0)
268 wxYield();
269
270 int exitcode = data->exitcode;
271
272 delete data;
273
274 return exitcode;
275 }
276 else
277 {
278 // async execution, nothing special to do - caller will be
279 // notified about the process terminationif process != NULL, data
280 // will be deleted in GTK_EndProcessDetector
281 data->process = process;
282 data->pid = pid;
283
284 return pid;
285 }
286 }
287 }
288
289 // ----------------------------------------------------------------------------
290 // file and directory functions
291 // ----------------------------------------------------------------------------
292
293 const char* wxGetHomeDir( wxString *home )
294 {
295 *home = wxGetUserHome( wxString() );
296 if ( home->IsEmpty() )
297 *home = "/";
298
299 return home->c_str();
300 }
301
302 char *wxGetUserHome( const wxString &user )
303 {
304 struct passwd *who = (struct passwd *) NULL;
305
306 if (user.IsNull() || (user== ""))
307 {
308 register char *ptr;
309
310 if ((ptr = getenv("HOME")) != NULL)
311 {
312 return ptr;
313 }
314 if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
315 {
316 who = getpwnam(ptr);
317 }
318
319 // We now make sure the the user exists!
320 if (who == NULL)
321 {
322 who = getpwuid(getuid());
323 }
324 }
325 else
326 {
327 who = getpwnam (user);
328 }
329
330 return who ? who->pw_dir : (char*)NULL;
331 }
332
333 // ----------------------------------------------------------------------------
334 // id routines
335 // ----------------------------------------------------------------------------
336
337 bool wxGetHostName(char *buf, int sz)
338 {
339 wxCHECK_MSG( buf, FALSE, "NULL pointer in wxGetHostName" );
340
341 *buf = '\0';
342
343 // we're using uname() which is POSIX instead of less standard sysinfo()
344 #if defined(HAVE_UNAME)
345 utsname uts;
346 bool ok = uname(&uts) != -1;
347 if ( ok )
348 {
349 strncpy(buf, uts.nodename, sz - 1);
350 buf[sz] = '\0';
351 }
352 #elif defined(HAVE_GETHOSTNAME)
353 bool ok = gethostname(buf, sz) != -1;
354 #else
355 wxFAIL_MSG("don't know host name for this machibe");
356
357 bool ok = FALSE;
358 #endif
359
360 if ( !ok )
361 {
362 wxLogSysError(_("Cannot get the hostname"));
363 }
364
365 return ok;
366 }
367
368 bool wxGetUserId(char *buf, int sz)
369 {
370 struct passwd *who;
371
372 *buf = '\0';
373 if ((who = getpwuid(getuid ())) != NULL)
374 {
375 strncpy (buf, who->pw_name, sz - 1);
376 return TRUE;
377 }
378
379 return FALSE;
380 }
381
382 bool wxGetUserName(char *buf, int sz)
383 {
384 struct passwd *who;
385 char *comma;
386
387 *buf = '\0';
388 if ((who = getpwuid (getuid ())) != NULL) {
389 comma = strchr(who->pw_gecos, ',');
390 if (comma)
391 *comma = '\0'; // cut off non-name comment fields
392 strncpy (buf, who->pw_gecos, sz - 1);
393 return TRUE;
394 }
395
396 return FALSE;
397 }
398
399 // ----------------------------------------------------------------------------
400 // error and debug output routines (deprecated, use wxLog)
401 // ----------------------------------------------------------------------------
402
403 void wxDebugMsg( const char *format, ... )
404 {
405 va_list ap;
406 va_start( ap, format );
407 vfprintf( stderr, format, ap );
408 fflush( stderr );
409 va_end(ap);
410 }
411
412 void wxError( const wxString &msg, const wxString &title )
413 {
414 fprintf( stderr, _("Error ") );
415 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
416 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
417 fprintf( stderr, ".\n" );
418 }
419
420 void wxFatalError( const wxString &msg, const wxString &title )
421 {
422 fprintf( stderr, _("Error ") );
423 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
424 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
425 fprintf( stderr, ".\n" );
426 exit(3); // the same exit code as for abort()
427 }
428
429 //------------------------------------------------------------------------
430 // directory routines
431 //------------------------------------------------------------------------
432
433 bool wxDirExists( const wxString& dir )
434 {
435 char buf[500];
436 strcpy( buf, WXSTRINGCAST(dir) );
437 struct stat sbuf;
438 return ((stat(buf, &sbuf) != -1) && S_ISDIR(sbuf.st_mode) ? TRUE : FALSE);
439 }