]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
wxUSE_THREADS typo corrected
[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 #include <ctype.h> // isspace()
43
44 // JACS: needed for FD_SETSIZE
45 #include <sys/time.h>
46
47 #if HAVE_UNAME
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.
58 #if !defined(HAVE_USLEEP) && \
59 (defined(__SUN__) && !defined(__SunOs_5_6) && \
60 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
61 defined(__osf__)
62 extern "C"
63 {
64 #ifdef __SUN__
65 int usleep(unsigned int usec);
66 #else // !Sun
67 void usleep(unsigned long usec);
68 #endif // Sun/!Sun
69 };
70 #endif // Unices without usleep()
71
72 // ============================================================================
73 // implementation
74 // ============================================================================
75
76 // ----------------------------------------------------------------------------
77 // sleeping
78 // ----------------------------------------------------------------------------
79
80 void wxSleep(int nSecs)
81 {
82 sleep(nSecs);
83 }
84
85 void wxUsleep(unsigned long milliseconds)
86 {
87 #if HAVE_NANOSLEEP
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);
94 #elif HAVE_USLEEP
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
99 #if defined(__SUN__) && wxUSE_THREADS
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
113 int wxKill(long pid, wxSignal sig)
114 {
115 return kill(pid, (int)sig);
116 }
117
118 #define WXEXECUTE_NARGS 127
119
120 long wxExecute( const wxString& command, bool sync, wxProcess *process )
121 {
122 wxCHECK_MSG( !command.IsEmpty(), 0, "can't exec empty command" );
123
124 int argc = 0;
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;
130
131 // split the command line in arguments
132 do
133 {
134 argument="";
135 quotechar = '\0';
136
137 // eat leading whitespace:
138 while ( isspace(*cptr) )
139 cptr++;
140
141 if ( *cptr == '\'' || *cptr == '"' )
142 quotechar = *cptr++;
143
144 do
145 {
146 if ( *cptr == '\\' && ! escaped )
147 {
148 escaped = TRUE;
149 cptr++;
150 continue;
151 }
152
153 // all other characters:
154 argument += *cptr++;
155 escaped = FALSE;
156
157 // have we reached the end of the argument?
158 if ( (*cptr == quotechar && ! escaped)
159 || (quotechar == '\0' && isspace(*cptr))
160 || *cptr == '\0' )
161 {
162 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
163 "too many arguments in wxExecute" );
164
165 argv[argc] = new char[argument.length() + 1];
166 strcpy(argv[argc], argument.c_str());
167 argc++;
168
169 // if not at end of buffer, swallow last character:
170 if(*cptr)
171 cptr++;
172
173 break; // done with this one, start over
174 }
175 } while(*cptr);
176 } while(*cptr);
177 argv[argc] = NULL;
178
179 // do execute the command
180 long lRc = wxExecute(argv, sync, process);
181
182 // clean up
183 argc = 0;
184 while( argv[argc] )
185 delete [] argv[argc++];
186
187 return lRc;
188 }
189
190 bool 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
201 void wxHandleProcessTermination(wxEndProcessData *proc_data)
202 {
203 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
204
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)
208 int status = 0;
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 }
222
223 // clean up
224 if ( proc_data->pid > 0 )
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
237 long 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
268 // one wants proper IO for the subprocess, the right thing to do is
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
290 execvp (*argv, argv);
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
340 const char* wxGetHomeDir( wxString *home )
341 {
342 *home = wxGetUserHome( wxString() );
343 if ( home->IsEmpty() )
344 *home = "/";
345
346 return home->c_str();
347 }
348
349 char *wxGetUserHome( const wxString &user )
350 {
351 struct passwd *who = (struct passwd *) NULL;
352
353 if ( !user )
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 // ----------------------------------------------------------------------------
381 // network and user id routines
382 // ----------------------------------------------------------------------------
383
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)
387 static bool wxGetHostNameInternal(char *buf, int sz)
388 {
389 wxCHECK_MSG( buf, FALSE, "NULL pointer in wxGetHostNameInternal" );
390
391 *buf = '\0';
392
393 // we're using uname() which is POSIX instead of less standard sysinfo()
394 #if defined(HAVE_UNAME)
395 struct utsname uts;
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;
404 #else // no uname, no gethostname
405 wxFAIL_MSG("don't know host name for this machibe");
406
407 bool ok = FALSE;
408 #endif // uname/gethostname
409
410 if ( !ok )
411 {
412 wxLogSysError(_("Cannot get the hostname"));
413 }
414
415 return ok;
416 }
417
418 bool 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
437 bool 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
464 bool 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
478 bool 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
499 void 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
508 void 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
516 void 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