]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
printf => wxLogTrace
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f
VZ
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()
fad866f4 42#include <ctype.h> // isspace()
0ed9a934 43
7bcb11d3
JS
44// JACS: needed for FD_SETSIZE
45#include <sys/time.h>
46
47#if HAVE_UNAME
518b5d2f
VZ
48 #include <sys/utsname.h> // for uname()
49#endif // HAVE_UNAME
50
51// ----------------------------------------------------------------------------
52// conditional compilation
53// ----------------------------------------------------------------------------
54
55// many versions of Unices have this function, but it is not defined in system
56// headers - please add your system here if it is the case for your OS.
57// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
1363811b
VZ
58#if !defined(HAVE_USLEEP) && \
59 (defined(__SUN__) && !defined(__SunOs_5_6) && \
518b5d2f
VZ
60 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
61 defined(__osf__)
62 extern "C"
63 {
1363811b
VZ
64 #ifdef __SUN__
65 int usleep(unsigned int usec);
66 #else // !Sun
67 void usleep(unsigned long usec);
68 #endif // Sun/!Sun
518b5d2f
VZ
69 };
70#endif // Unices without usleep()
71
518b5d2f
VZ
72// ============================================================================
73// implementation
74// ============================================================================
75
76// ----------------------------------------------------------------------------
77// sleeping
78// ----------------------------------------------------------------------------
79
80void wxSleep(int nSecs)
81{
82 sleep(nSecs);
83}
84
85void wxUsleep(unsigned long milliseconds)
86{
7bcb11d3 87#if HAVE_NANOSLEEP
518b5d2f
VZ
88 timespec tmReq;
89 tmReq.tv_sec = milliseconds / 1000;
90 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
91
92 // we're not interested in remaining time nor in return value
93 (void)nanosleep(&tmReq, (timespec *)NULL);
7bcb11d3 94#elif HAVE_USLEEP
518b5d2f
VZ
95 // uncomment this if you feel brave or if you are sure that your version
96 // of Solaris has a safe usleep() function but please notice that usleep()
97 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
98 // documented as MT-Safe
ea18eed9 99 #if defined(__SUN__) && wxUSE_THREADS
518b5d2f
VZ
100 #error "usleep() cannot be used in MT programs under Solaris."
101 #endif // Sun
102
103 usleep(milliseconds * 1000); // usleep(3) wants microseconds
104#else // !sleep function
105 #error "usleep() or nanosleep() function required for wxUsleep"
106#endif // sleep function
107}
108
109// ----------------------------------------------------------------------------
110// process management
111// ----------------------------------------------------------------------------
112
0fb67cd1 113int wxKill(long pid, wxSignal sig)
518b5d2f 114{
0fb67cd1 115 return kill(pid, (int)sig);
518b5d2f
VZ
116}
117
fad866f4
KB
118#define WXEXECUTE_NARGS 127
119
518b5d2f
VZ
120long wxExecute( const wxString& command, bool sync, wxProcess *process )
121{
05079acc 122 wxCHECK_MSG( !command.IsEmpty(), 0, _T("can't exec empty command") );
518b5d2f
VZ
123
124 int argc = 0;
05079acc 125 wxChar *argv[WXEXECUTE_NARGS];
fad866f4 126 wxString argument;
05079acc
OK
127 const wxChar *cptr = command.c_str();
128 wxChar quotechar = _T('\0'); // is arg quoted?
fad866f4 129 bool escaped = FALSE;
518b5d2f 130
0ed9a934 131 // split the command line in arguments
fad866f4
KB
132 do
133 {
05079acc
OK
134 argument=_T("");
135 quotechar = _T('\0');
0ed9a934 136
fad866f4 137 // eat leading whitespace:
05079acc 138 while ( wxIsspace(*cptr) )
fad866f4 139 cptr++;
0ed9a934 140
05079acc 141 if ( *cptr == _T('\'') || *cptr == _T('"') )
fad866f4 142 quotechar = *cptr++;
0ed9a934 143
fad866f4
KB
144 do
145 {
05079acc 146 if ( *cptr == _T('\\') && ! escaped )
fad866f4
KB
147 {
148 escaped = TRUE;
149 cptr++;
150 continue;
151 }
0ed9a934 152
fad866f4 153 // all other characters:
0ed9a934 154 argument += *cptr++;
fad866f4 155 escaped = FALSE;
0ed9a934
VZ
156
157 // have we reached the end of the argument?
158 if ( (*cptr == quotechar && ! escaped)
05079acc
OK
159 || (quotechar == _T('\0') && wxIsspace(*cptr))
160 || *cptr == _T('\0') )
fad866f4 161 {
0ed9a934 162 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
05079acc 163 _T("too many arguments in wxExecute") );
0ed9a934 164
05079acc
OK
165 argv[argc] = new wxChar[argument.length() + 1];
166 wxStrcpy(argv[argc], argument.c_str());
fad866f4 167 argc++;
0ed9a934 168
fad866f4 169 // if not at end of buffer, swallow last character:
0ed9a934
VZ
170 if(*cptr)
171 cptr++;
172
fad866f4
KB
173 break; // done with this one, start over
174 }
0ed9a934
VZ
175 } while(*cptr);
176 } while(*cptr);
fad866f4 177 argv[argc] = NULL;
0ed9a934
VZ
178
179 // do execute the command
518b5d2f
VZ
180 long lRc = wxExecute(argv, sync, process);
181
0ed9a934 182 // clean up
fad866f4 183 argc = 0;
0ed9a934 184 while( argv[argc] )
fad866f4 185 delete [] argv[argc++];
518b5d2f
VZ
186
187 return lRc;
188}
189
190bool wxShell(const wxString& command)
191{
192 wxString cmd;
193 if ( !!command )
05079acc 194 cmd.Printf(_T("xterm -e %s"), command.c_str());
518b5d2f
VZ
195 else
196 cmd = command;
197
198 return wxExecute(cmd) != 0;
199}
200
201void wxHandleProcessTermination(wxEndProcessData *proc_data)
202{
203 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
204
0ed9a934
VZ
205 // waitpid is POSIX so should be available everywhere, however on older
206 // systems wait() might be used instead in a loop (until the right pid
207 // terminates)
518b5d2f 208 int status = 0;
0ed9a934
VZ
209 if ( waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) )
210 {
211 wxLogSysError(_("Waiting for subprocess termination failed"));
212 }
213 else
214 {
215 // notify user about termination if required
216 if (proc_data->process)
217 {
218 proc_data->process->OnTerminate(proc_data->pid,
219 WEXITSTATUS(status));
220 }
221 }
518b5d2f 222
0ed9a934
VZ
223 // clean up
224 if ( proc_data->pid > 0 )
518b5d2f
VZ
225 {
226 delete proc_data;
227 }
228 else
229 {
230 // wxExecute() will know about it
231 proc_data->exitcode = status;
232
233 proc_data->pid = 0;
234 }
235}
236
05079acc 237long wxExecute( wxChar **argv, bool sync, wxProcess *process )
518b5d2f 238{
05079acc 239 wxCHECK_MSG( *argv, 0, _T("can't exec empty command") );
518b5d2f
VZ
240
241 int end_proc_detect[2];
05079acc
OK
242#if wxUSE_UNICODE
243 int mb_argc = 0;
244 char *mb_argv[WXEXECUTE_NARGS];
245
246 while (argv[mb_argc]) {
247 wxWX2MBbuf mb_arg = wxConv_libc.cWX2MB(argv[mb_argc]);
248 mb_argv[mb_argc] = strdup(mb_arg);
249 mb_argc++;
250 }
251 mb_argv[mb_argc] = (char *) NULL;
252#else
253 wxChar **mb_argv = argv;
254#endif
518b5d2f
VZ
255
256 // create pipes
257 if (pipe(end_proc_detect) == -1)
258 {
259 wxLogSysError( _("Pipe creation failed") );
260 return 0;
261 }
262
263 // fork the process
264#ifdef HAVE_VFORK
265 pid_t pid = vfork();
266#else
267 pid_t pid = fork();
268#endif
269 if (pid == -1)
270 {
271 wxLogSysError( _("Fork failed") );
272 return 0;
273 }
274 else if (pid == 0)
275 {
276 // we're in child
277 close(end_proc_detect[0]); // close reading side
278
279 // These three lines close the open file descriptors to to avoid any
280 // input/output which might block the process or irritate the user. If
d6086ea6 281 // one wants proper IO for the subprocess, the right thing to do is
518b5d2f
VZ
282 // to start an xterm executing it.
283 if (sync == 0)
284 {
285 // leave stderr opened, it won't do any hurm
286 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
287 {
288 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
289 close(fd);
290 }
291 }
292
293#if 0
294 close(STDERR_FILENO);
295
296 // some programs complain about stderr not being open, so redirect
297 // them:
298 open("/dev/null", O_RDONLY); // stdin
299 open("/dev/null", O_WRONLY); // stdout
300 open("/dev/null", O_WRONLY); // stderr
301#endif
302
05079acc 303 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
304
305 // there is no return after successful exec()
05079acc 306 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
518b5d2f
VZ
307
308 _exit(-1);
309 }
310 else
311 {
312 // we're in parent
313 close(end_proc_detect[1]); // close writing side
314
315 wxEndProcessData *data = new wxEndProcessData;
316 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
317
05079acc
OK
318#if wxUSE_UNICODE
319 mb_argc = 0;
320 while (mb_argv[mb_argc])
321 free(mb_argv[mb_argc++]);
322#endif
323
518b5d2f
VZ
324 if ( sync )
325 {
05079acc 326 wxASSERT_MSG( !process, _T("wxProcess param ignored for sync exec") );
518b5d2f
VZ
327 data->process = NULL;
328
329 // sync execution: indicate it by negating the pid
330 data->pid = -pid;
331
332 // it will be set to 0 from GTK_EndProcessDetector
333 while (data->pid != 0)
334 wxYield();
335
336 int exitcode = data->exitcode;
337
338 delete data;
339
340 return exitcode;
341 }
342 else
343 {
344 // async execution, nothing special to do - caller will be
345 // notified about the process terminationif process != NULL, data
346 // will be deleted in GTK_EndProcessDetector
347 data->process = process;
348 data->pid = pid;
349
350 return pid;
351 }
352 }
353}
354
355// ----------------------------------------------------------------------------
356// file and directory functions
357// ----------------------------------------------------------------------------
358
05079acc 359const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
360{
361 *home = wxGetUserHome( wxString() );
362 if ( home->IsEmpty() )
05079acc 363 *home = _T("/");
518b5d2f
VZ
364
365 return home->c_str();
366}
367
05079acc
OK
368#if wxUSE_UNICODE
369const wxMB2WXbuf wxGetUserHome( const wxString &user )
370#else // just for binary compatibility
518b5d2f 371char *wxGetUserHome( const wxString &user )
05079acc 372#endif
518b5d2f
VZ
373{
374 struct passwd *who = (struct passwd *) NULL;
375
0fb67cd1 376 if ( !user )
518b5d2f 377 {
05079acc 378 register wxChar *ptr;
518b5d2f 379
05079acc 380 if ((ptr = wxGetenv(_T("HOME"))) != NULL)
518b5d2f
VZ
381 {
382 return ptr;
383 }
05079acc 384 if ((ptr = wxGetenv(_T("USER"))) != NULL || (ptr = wxGetenv(_T("LOGNAME"))) != NULL)
518b5d2f 385 {
05079acc 386 who = getpwnam(wxConv_libc.cWX2MB(ptr));
518b5d2f
VZ
387 }
388
389 // We now make sure the the user exists!
390 if (who == NULL)
391 {
392 who = getpwuid(getuid());
393 }
394 }
395 else
396 {
05079acc 397 who = getpwnam (user.mb_str());
518b5d2f
VZ
398 }
399
05079acc
OK
400#if wxUSE_UNICODE
401 return who ? wxConv_libc.cMB2WX(who->pw_dir) : (wxMB2WXbuf)((wxChar*)NULL);
402#else
403 return who ? who->pw_dir : ((char*)NULL);
404#endif
518b5d2f
VZ
405}
406
407// ----------------------------------------------------------------------------
0fb67cd1 408// network and user id routines
518b5d2f
VZ
409// ----------------------------------------------------------------------------
410
0fb67cd1
VZ
411// retrieve either the hostname or FQDN depending on platform (caller must
412// check whether it's one or the other, this is why this function is for
413// private use only)
05079acc 414static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 415{
05079acc 416 wxCHECK_MSG( buf, FALSE, _T("NULL pointer in wxGetHostNameInternal") );
518b5d2f 417
05079acc 418 *buf = _T('\0');
518b5d2f
VZ
419
420 // we're using uname() which is POSIX instead of less standard sysinfo()
421#if defined(HAVE_UNAME)
cc743a6f 422 struct utsname uts;
518b5d2f
VZ
423 bool ok = uname(&uts) != -1;
424 if ( ok )
425 {
05079acc
OK
426 wxStrncpy(buf, wxConv_libc.cMB2WX(uts.nodename), sz - 1);
427 buf[sz] = _T('\0');
518b5d2f
VZ
428 }
429#elif defined(HAVE_GETHOSTNAME)
430 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 431#else // no uname, no gethostname
05079acc 432 wxFAIL_MSG(_T("don't know host name for this machine"));
518b5d2f
VZ
433
434 bool ok = FALSE;
0fb67cd1 435#endif // uname/gethostname
518b5d2f
VZ
436
437 if ( !ok )
438 {
439 wxLogSysError(_("Cannot get the hostname"));
440 }
441
442 return ok;
443}
444
05079acc 445bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
446{
447 bool ok = wxGetHostNameInternal(buf, sz);
448
449 if ( ok )
450 {
451 // BSD systems return the FQDN, we only want the hostname, so extract
452 // it (we consider that dots are domain separators)
05079acc 453 wxChar *dot = wxStrchr(buf, _T('.'));
0fb67cd1
VZ
454 if ( dot )
455 {
456 // nuke it
05079acc 457 *dot = _T('\0');
0fb67cd1
VZ
458 }
459 }
460
461 return ok;
462}
463
05079acc 464bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
465{
466 bool ok = wxGetHostNameInternal(buf, sz);
467
468 if ( ok )
469 {
05079acc 470 if ( !wxStrchr(buf, _T('.')) )
0fb67cd1 471 {
05079acc 472 struct hostent *host = gethostbyname(wxConv_libc.cWX2MB(buf));
0fb67cd1
VZ
473 if ( !host )
474 {
475 wxLogSysError(_("Cannot get the official hostname"));
476
477 ok = FALSE;
478 }
479 else
480 {
481 // the canonical name
05079acc 482 wxStrncpy(buf, wxConv_libc.cMB2WX(host->h_name), sz);
0fb67cd1
VZ
483 }
484 }
485 //else: it's already a FQDN (BSD behaves this way)
486 }
487
488 return ok;
489}
490
05079acc 491bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
492{
493 struct passwd *who;
494
05079acc 495 *buf = _T('\0');
518b5d2f
VZ
496 if ((who = getpwuid(getuid ())) != NULL)
497 {
05079acc 498 wxStrncpy (buf, wxConv_libc.cMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
499 return TRUE;
500 }
501
502 return FALSE;
503}
504
05079acc 505bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
506{
507 struct passwd *who;
508 char *comma;
509
05079acc 510 *buf = _T('\0');
518b5d2f
VZ
511 if ((who = getpwuid (getuid ())) != NULL) {
512 comma = strchr(who->pw_gecos, ',');
513 if (comma)
514 *comma = '\0'; // cut off non-name comment fields
05079acc 515 wxStrncpy (buf, wxConv_libc.cMB2WX(who->pw_gecos), sz - 1);
518b5d2f
VZ
516 return TRUE;
517 }
518
519 return FALSE;
520}
521
522// ----------------------------------------------------------------------------
523// error and debug output routines (deprecated, use wxLog)
524// ----------------------------------------------------------------------------
525
526void wxDebugMsg( const char *format, ... )
527{
528 va_list ap;
529 va_start( ap, format );
530 vfprintf( stderr, format, ap );
531 fflush( stderr );
532 va_end(ap);
533}
534
535void wxError( const wxString &msg, const wxString &title )
536{
05079acc
OK
537 wxFprintf( stderr, _("Error ") );
538 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
539 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
540 wxFprintf( stderr, _T(".\n") );
518b5d2f
VZ
541}
542
543void wxFatalError( const wxString &msg, const wxString &title )
544{
05079acc
OK
545 wxFprintf( stderr, _("Error ") );
546 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
547 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
548 wxFprintf( stderr, _T(".\n") );
518b5d2f
VZ
549 exit(3); // the same exit code as for abort()
550}