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