]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
wxUSE_THREADS typo corrected
[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{
518b5d2f
VZ
122 wxCHECK_MSG( !command.IsEmpty(), 0, "can't exec empty command" );
123
124 int argc = 0;
fad866f4
KB
125 char *argv[WXEXECUTE_NARGS];
126 wxString argument;
127 const char *cptr = command.c_str();
128 char quotechar = '\0'; // is arg quoted?
129 bool escaped = FALSE;
518b5d2f 130
0ed9a934 131 // split the command line in arguments
fad866f4
KB
132 do
133 {
134 argument="";
135 quotechar = '\0';
0ed9a934 136
fad866f4 137 // eat leading whitespace:
0ed9a934 138 while ( isspace(*cptr) )
fad866f4 139 cptr++;
0ed9a934
VZ
140
141 if ( *cptr == '\'' || *cptr == '"' )
fad866f4 142 quotechar = *cptr++;
0ed9a934 143
fad866f4
KB
144 do
145 {
0ed9a934 146 if ( *cptr == '\\' && ! 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)
159 || (quotechar == '\0' && isspace(*cptr))
160 || *cptr == '\0' )
fad866f4 161 {
0ed9a934
VZ
162 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
163 "too many arguments in wxExecute" );
164
165 argv[argc] = new char[argument.length() + 1];
fad866f4
KB
166 strcpy(argv[argc], argument.c_str());
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 )
194 cmd.Printf("xterm -e %s", command.c_str());
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
237long wxExecute( char **argv, bool sync, wxProcess *process )
238{
239 wxCHECK_MSG( *argv, 0, "can't exec empty command" );
240
241 int end_proc_detect[2];
242
243 // create pipes
244 if (pipe(end_proc_detect) == -1)
245 {
246 wxLogSysError( _("Pipe creation failed") );
247 return 0;
248 }
249
250 // fork the process
251#ifdef HAVE_VFORK
252 pid_t pid = vfork();
253#else
254 pid_t pid = fork();
255#endif
256 if (pid == -1)
257 {
258 wxLogSysError( _("Fork failed") );
259 return 0;
260 }
261 else if (pid == 0)
262 {
263 // we're in child
264 close(end_proc_detect[0]); // close reading side
265
266 // These three lines close the open file descriptors to to avoid any
267 // input/output which might block the process or irritate the user. If
d6086ea6 268 // one wants proper IO for the subprocess, the right thing to do is
518b5d2f
VZ
269 // to start an xterm executing it.
270 if (sync == 0)
271 {
272 // leave stderr opened, it won't do any hurm
273 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
274 {
275 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
276 close(fd);
277 }
278 }
279
280#if 0
281 close(STDERR_FILENO);
282
283 // some programs complain about stderr not being open, so redirect
284 // them:
285 open("/dev/null", O_RDONLY); // stdin
286 open("/dev/null", O_WRONLY); // stdout
287 open("/dev/null", O_WRONLY); // stderr
288#endif
289
518b5d2f 290 execvp (*argv, argv);
518b5d2f
VZ
291
292 // there is no return after successful exec()
293 fprintf(stderr, _("Can't execute '%s'\n"), *argv);
294
295 _exit(-1);
296 }
297 else
298 {
299 // we're in parent
300 close(end_proc_detect[1]); // close writing side
301
302 wxEndProcessData *data = new wxEndProcessData;
303 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
304
305 if ( sync )
306 {
307 wxASSERT_MSG( !process, "wxProcess param ignored for sync exec" );
308 data->process = NULL;
309
310 // sync execution: indicate it by negating the pid
311 data->pid = -pid;
312
313 // it will be set to 0 from GTK_EndProcessDetector
314 while (data->pid != 0)
315 wxYield();
316
317 int exitcode = data->exitcode;
318
319 delete data;
320
321 return exitcode;
322 }
323 else
324 {
325 // async execution, nothing special to do - caller will be
326 // notified about the process terminationif process != NULL, data
327 // will be deleted in GTK_EndProcessDetector
328 data->process = process;
329 data->pid = pid;
330
331 return pid;
332 }
333 }
334}
335
336// ----------------------------------------------------------------------------
337// file and directory functions
338// ----------------------------------------------------------------------------
339
340const char* wxGetHomeDir( wxString *home )
341{
342 *home = wxGetUserHome( wxString() );
343 if ( home->IsEmpty() )
344 *home = "/";
345
346 return home->c_str();
347}
348
349char *wxGetUserHome( const wxString &user )
350{
351 struct passwd *who = (struct passwd *) NULL;
352
0fb67cd1 353 if ( !user )
518b5d2f
VZ
354 {
355 register char *ptr;
356
357 if ((ptr = getenv("HOME")) != NULL)
358 {
359 return ptr;
360 }
361 if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
362 {
363 who = getpwnam(ptr);
364 }
365
366 // We now make sure the the user exists!
367 if (who == NULL)
368 {
369 who = getpwuid(getuid());
370 }
371 }
372 else
373 {
374 who = getpwnam (user);
375 }
376
377 return who ? who->pw_dir : (char*)NULL;
378}
379
380// ----------------------------------------------------------------------------
0fb67cd1 381// network and user id routines
518b5d2f
VZ
382// ----------------------------------------------------------------------------
383
0fb67cd1
VZ
384// retrieve either the hostname or FQDN depending on platform (caller must
385// check whether it's one or the other, this is why this function is for
386// private use only)
387static bool wxGetHostNameInternal(char *buf, int sz)
518b5d2f 388{
0fb67cd1 389 wxCHECK_MSG( buf, FALSE, "NULL pointer in wxGetHostNameInternal" );
518b5d2f
VZ
390
391 *buf = '\0';
392
393 // we're using uname() which is POSIX instead of less standard sysinfo()
394#if defined(HAVE_UNAME)
cc743a6f 395 struct utsname uts;
518b5d2f
VZ
396 bool ok = uname(&uts) != -1;
397 if ( ok )
398 {
399 strncpy(buf, uts.nodename, sz - 1);
400 buf[sz] = '\0';
401 }
402#elif defined(HAVE_GETHOSTNAME)
403 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 404#else // no uname, no gethostname
518b5d2f
VZ
405 wxFAIL_MSG("don't know host name for this machibe");
406
407 bool ok = FALSE;
0fb67cd1 408#endif // uname/gethostname
518b5d2f
VZ
409
410 if ( !ok )
411 {
412 wxLogSysError(_("Cannot get the hostname"));
413 }
414
415 return ok;
416}
417
0fb67cd1
VZ
418bool wxGetHostName(char *buf, int sz)
419{
420 bool ok = wxGetHostNameInternal(buf, sz);
421
422 if ( ok )
423 {
424 // BSD systems return the FQDN, we only want the hostname, so extract
425 // it (we consider that dots are domain separators)
426 char *dot = strchr(buf, '.');
427 if ( dot )
428 {
429 // nuke it
430 *dot = '\0';
431 }
432 }
433
434 return ok;
435}
436
437bool wxGetFullHostName(char *buf, int sz)
438{
439 bool ok = wxGetHostNameInternal(buf, sz);
440
441 if ( ok )
442 {
443 if ( !strchr(buf, '.') )
444 {
445 struct hostent *host = gethostbyname(buf);
446 if ( !host )
447 {
448 wxLogSysError(_("Cannot get the official hostname"));
449
450 ok = FALSE;
451 }
452 else
453 {
454 // the canonical name
455 strncpy(buf, host->h_name, sz);
456 }
457 }
458 //else: it's already a FQDN (BSD behaves this way)
459 }
460
461 return ok;
462}
463
518b5d2f
VZ
464bool wxGetUserId(char *buf, int sz)
465{
466 struct passwd *who;
467
468 *buf = '\0';
469 if ((who = getpwuid(getuid ())) != NULL)
470 {
471 strncpy (buf, who->pw_name, sz - 1);
472 return TRUE;
473 }
474
475 return FALSE;
476}
477
478bool wxGetUserName(char *buf, int sz)
479{
480 struct passwd *who;
481 char *comma;
482
483 *buf = '\0';
484 if ((who = getpwuid (getuid ())) != NULL) {
485 comma = strchr(who->pw_gecos, ',');
486 if (comma)
487 *comma = '\0'; // cut off non-name comment fields
488 strncpy (buf, who->pw_gecos, sz - 1);
489 return TRUE;
490 }
491
492 return FALSE;
493}
494
495// ----------------------------------------------------------------------------
496// error and debug output routines (deprecated, use wxLog)
497// ----------------------------------------------------------------------------
498
499void wxDebugMsg( const char *format, ... )
500{
501 va_list ap;
502 va_start( ap, format );
503 vfprintf( stderr, format, ap );
504 fflush( stderr );
505 va_end(ap);
506}
507
508void wxError( const wxString &msg, const wxString &title )
509{
510 fprintf( stderr, _("Error ") );
511 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
512 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
513 fprintf( stderr, ".\n" );
514}
515
516void wxFatalError( const wxString &msg, const wxString &title )
517{
518 fprintf( stderr, _("Error ") );
519 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
520 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
521 fprintf( stderr, ".\n" );
522 exit(3); // the same exit code as for abort()
523}
524