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