]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
Updated distribtion and docs.
[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") );
5fbecd99
OK
260#if wxUSE_UNICODE
261 mb_argc = 0;
262 while (mb_argv[mb_argc])
263 free(mb_argv[mb_argc++]);
264#endif
518b5d2f
VZ
265 return 0;
266 }
267
268 // fork the process
269#ifdef HAVE_VFORK
270 pid_t pid = vfork();
271#else
272 pid_t pid = fork();
273#endif
274 if (pid == -1)
275 {
276 wxLogSysError( _("Fork failed") );
5fbecd99
OK
277#if wxUSE_UNICODE
278 mb_argc = 0;
279 while (mb_argv[mb_argc])
280 free(mb_argv[mb_argc++]);
281#endif
518b5d2f
VZ
282 return 0;
283 }
284 else if (pid == 0)
285 {
286 // we're in child
287 close(end_proc_detect[0]); // close reading side
288
289 // These three lines close the open file descriptors to to avoid any
290 // input/output which might block the process or irritate the user. If
d6086ea6 291 // one wants proper IO for the subprocess, the right thing to do is
518b5d2f
VZ
292 // to start an xterm executing it.
293 if (sync == 0)
294 {
295 // leave stderr opened, it won't do any hurm
296 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
297 {
298 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
299 close(fd);
300 }
301 }
302
303#if 0
304 close(STDERR_FILENO);
305
306 // some programs complain about stderr not being open, so redirect
307 // them:
308 open("/dev/null", O_RDONLY); // stdin
309 open("/dev/null", O_WRONLY); // stdout
310 open("/dev/null", O_WRONLY); // stderr
311#endif
312
05079acc 313 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
314
315 // there is no return after successful exec()
05079acc 316 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
518b5d2f
VZ
317
318 _exit(-1);
319 }
320 else
321 {
322 // we're in parent
323 close(end_proc_detect[1]); // close writing side
324
325 wxEndProcessData *data = new wxEndProcessData;
326 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
327
05079acc
OK
328#if wxUSE_UNICODE
329 mb_argc = 0;
330 while (mb_argv[mb_argc])
331 free(mb_argv[mb_argc++]);
332#endif
333
518b5d2f
VZ
334 if ( sync )
335 {
05079acc 336 wxASSERT_MSG( !process, _T("wxProcess param ignored for sync exec") );
518b5d2f
VZ
337 data->process = NULL;
338
339 // sync execution: indicate it by negating the pid
340 data->pid = -pid;
341
342 // it will be set to 0 from GTK_EndProcessDetector
343 while (data->pid != 0)
344 wxYield();
345
346 int exitcode = data->exitcode;
347
348 delete data;
349
350 return exitcode;
351 }
352 else
353 {
354 // async execution, nothing special to do - caller will be
355 // notified about the process terminationif process != NULL, data
356 // will be deleted in GTK_EndProcessDetector
357 data->process = process;
358 data->pid = pid;
359
360 return pid;
361 }
362 }
363}
364
365// ----------------------------------------------------------------------------
366// file and directory functions
367// ----------------------------------------------------------------------------
368
05079acc 369const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
370{
371 *home = wxGetUserHome( wxString() );
372 if ( home->IsEmpty() )
05079acc 373 *home = _T("/");
518b5d2f
VZ
374
375 return home->c_str();
376}
377
05079acc
OK
378#if wxUSE_UNICODE
379const wxMB2WXbuf wxGetUserHome( const wxString &user )
380#else // just for binary compatibility
518b5d2f 381char *wxGetUserHome( const wxString &user )
05079acc 382#endif
518b5d2f
VZ
383{
384 struct passwd *who = (struct passwd *) NULL;
385
0fb67cd1 386 if ( !user )
518b5d2f 387 {
05079acc 388 register wxChar *ptr;
518b5d2f 389
05079acc 390 if ((ptr = wxGetenv(_T("HOME"))) != NULL)
518b5d2f
VZ
391 {
392 return ptr;
393 }
05079acc 394 if ((ptr = wxGetenv(_T("USER"))) != NULL || (ptr = wxGetenv(_T("LOGNAME"))) != NULL)
518b5d2f 395 {
05079acc 396 who = getpwnam(wxConv_libc.cWX2MB(ptr));
518b5d2f
VZ
397 }
398
399 // We now make sure the the user exists!
400 if (who == NULL)
401 {
402 who = getpwuid(getuid());
403 }
404 }
405 else
406 {
05079acc 407 who = getpwnam (user.mb_str());
518b5d2f
VZ
408 }
409
05079acc
OK
410#if wxUSE_UNICODE
411 return who ? wxConv_libc.cMB2WX(who->pw_dir) : (wxMB2WXbuf)((wxChar*)NULL);
412#else
413 return who ? who->pw_dir : ((char*)NULL);
414#endif
518b5d2f
VZ
415}
416
417// ----------------------------------------------------------------------------
0fb67cd1 418// network and user id routines
518b5d2f
VZ
419// ----------------------------------------------------------------------------
420
0fb67cd1
VZ
421// retrieve either the hostname or FQDN depending on platform (caller must
422// check whether it's one or the other, this is why this function is for
423// private use only)
05079acc 424static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 425{
05079acc 426 wxCHECK_MSG( buf, FALSE, _T("NULL pointer in wxGetHostNameInternal") );
518b5d2f 427
05079acc 428 *buf = _T('\0');
518b5d2f
VZ
429
430 // we're using uname() which is POSIX instead of less standard sysinfo()
431#if defined(HAVE_UNAME)
cc743a6f 432 struct utsname uts;
518b5d2f
VZ
433 bool ok = uname(&uts) != -1;
434 if ( ok )
435 {
05079acc
OK
436 wxStrncpy(buf, wxConv_libc.cMB2WX(uts.nodename), sz - 1);
437 buf[sz] = _T('\0');
518b5d2f
VZ
438 }
439#elif defined(HAVE_GETHOSTNAME)
440 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 441#else // no uname, no gethostname
05079acc 442 wxFAIL_MSG(_T("don't know host name for this machine"));
518b5d2f
VZ
443
444 bool ok = FALSE;
0fb67cd1 445#endif // uname/gethostname
518b5d2f
VZ
446
447 if ( !ok )
448 {
449 wxLogSysError(_("Cannot get the hostname"));
450 }
451
452 return ok;
453}
454
05079acc 455bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
456{
457 bool ok = wxGetHostNameInternal(buf, sz);
458
459 if ( ok )
460 {
461 // BSD systems return the FQDN, we only want the hostname, so extract
462 // it (we consider that dots are domain separators)
05079acc 463 wxChar *dot = wxStrchr(buf, _T('.'));
0fb67cd1
VZ
464 if ( dot )
465 {
466 // nuke it
05079acc 467 *dot = _T('\0');
0fb67cd1
VZ
468 }
469 }
470
471 return ok;
472}
473
05079acc 474bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
475{
476 bool ok = wxGetHostNameInternal(buf, sz);
477
478 if ( ok )
479 {
05079acc 480 if ( !wxStrchr(buf, _T('.')) )
0fb67cd1 481 {
05079acc 482 struct hostent *host = gethostbyname(wxConv_libc.cWX2MB(buf));
0fb67cd1
VZ
483 if ( !host )
484 {
485 wxLogSysError(_("Cannot get the official hostname"));
486
487 ok = FALSE;
488 }
489 else
490 {
491 // the canonical name
05079acc 492 wxStrncpy(buf, wxConv_libc.cMB2WX(host->h_name), sz);
0fb67cd1
VZ
493 }
494 }
495 //else: it's already a FQDN (BSD behaves this way)
496 }
497
498 return ok;
499}
500
05079acc 501bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
502{
503 struct passwd *who;
504
05079acc 505 *buf = _T('\0');
518b5d2f
VZ
506 if ((who = getpwuid(getuid ())) != NULL)
507 {
05079acc 508 wxStrncpy (buf, wxConv_libc.cMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
509 return TRUE;
510 }
511
512 return FALSE;
513}
514
05079acc 515bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
516{
517 struct passwd *who;
518 char *comma;
519
05079acc 520 *buf = _T('\0');
518b5d2f
VZ
521 if ((who = getpwuid (getuid ())) != NULL) {
522 comma = strchr(who->pw_gecos, ',');
523 if (comma)
524 *comma = '\0'; // cut off non-name comment fields
05079acc 525 wxStrncpy (buf, wxConv_libc.cMB2WX(who->pw_gecos), sz - 1);
518b5d2f
VZ
526 return TRUE;
527 }
528
529 return FALSE;
530}
531
532// ----------------------------------------------------------------------------
533// error and debug output routines (deprecated, use wxLog)
534// ----------------------------------------------------------------------------
535
536void wxDebugMsg( const char *format, ... )
537{
538 va_list ap;
539 va_start( ap, format );
540 vfprintf( stderr, format, ap );
541 fflush( stderr );
542 va_end(ap);
543}
544
545void wxError( const wxString &msg, const wxString &title )
546{
05079acc
OK
547 wxFprintf( stderr, _("Error ") );
548 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
549 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
550 wxFprintf( stderr, _T(".\n") );
518b5d2f
VZ
551}
552
553void wxFatalError( const wxString &msg, const wxString &title )
554{
05079acc
OK
555 wxFprintf( stderr, _("Error ") );
556 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
557 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
558 wxFprintf( stderr, _T(".\n") );
518b5d2f
VZ
559 exit(3); // the same exit code as for abort()
560}