remove OSF1 support
[oweals/cde.git] / cde / lib / tt / lib / util / tt_port.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $TOG: tt_port.C /main/5 1999/10/14 19:02:43 mgreess $                                                     
28 /* @(#)tt_port.C        1.20 93/09/07
29  *
30  * tt_port.cc
31  *
32  * Routines for centralizing non-portable constructs.
33  *
34  * Copyright (c) 1992 by Sun Microsystems, Inc.
35  */
36
37 #include "tt_options.h"
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <sys/param.h>
41 #include <string.h>
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <syslog.h>
48 #if defined(OPT_BUG_HPUX) && !defined(hpV4)
49 extern "C" {
50         int syslog(int priority, const char *message, ...);
51         int openlog(const char *ident, int logopt, int facility);
52 }
53 #endif
54 #if defined(sun)
55 #include <sys/utsname.h>
56 #endif
57 #include <errno.h>
58 #include "tt_port.h"
59 #include "tt_global_env.h"
60 #include "tt_string.h"
61
62 #if defined(OPT_BUG_SUNOS_4)
63 #       if defined(__GNUG__)
64 #               define uname NotAnAnsiCPrototypeForUname
65 #               include <sys/utsname.h>
66 #               undef uname
67                 extern "C" { int uname( struct utsname * ); }
68 #       else
69 #               include <sysent.h>
70 #               include <sys/utsname.h>
71 #       endif
72 #else
73 #       include <sys/utsname.h>
74 #endif
75
76 #if defined(OPT_SYSINFO)
77 #       include <sys/systeminfo.h>
78 #else
79 #       include <stdlib.h>      // atol()
80 #endif
81
82 #if defined(OPT_BUG_SGI) || defined(OPT_BUG_AIX)
83         extern "C" {extern int getdtablesize(void);}
84 #endif
85
86
87 /*
88  * Get the name of the host.
89  */
90 _Tt_string
91 _tt_gethostname()
92 {
93         /*
94          * If for some reason we can't get a host name, use "localhost".
95          * This at least has a chance of doing the right thing, say on
96          * a non-networked machine, and so is more useful than just returning
97          * null or an error and having our callers bail out.
98          */
99
100         const char *default_hostname = "localhost";
101         _Tt_string result;
102
103 #if !defined(OPT_GETHOSTNAME)
104         struct utsname uts_name;
105         
106
107         if (uname(&uts_name) >= 0) {
108                 result = uts_name.nodename;
109         } else {
110                 result = default_hostname;
111         }
112 #else
113         // It's not completely clear to me whether or not MAXHOSTNAMELEN is
114         // supposed to have room for the null byte at the end.  Leave an
115         // extra byte just to be sure.
116         
117         char curhostname[MAXHOSTNAMELEN+1];
118         if (0==gethostname(curhostname, sizeof curhostname)) {
119                 result = curhostname;
120         } else {
121                 result = default_hostname;
122         }
123 #endif /* OPT_GETHOSTNAME */
124
125         return result;
126 }
127
128 /*
129  * Get the number of currently possible file descriptors.
130  */
131 int
132 _tt_getdtablesize(void)
133 {
134 #if !defined(OPT_GETDTABLESIZE)
135         struct rlimit rl;
136         if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
137                 return (int)rl.rlim_cur;
138         } else {
139                 return 0;
140         }
141 #else
142         return getdtablesize();
143 #endif /* OPT_GETDTABLESIZE */
144 }
145
146
147 static struct rlimit original_dtablesize = { 0, 0 };
148 /*
149  * Maximize the number of possible file descriptors.
150  *
151  * Returns
152  *      0       Success
153  *      -1      Error (errno is set)
154  */
155 int
156 _tt_zoomdtablesize(void)
157 {
158 #if defined(_AIX)
159         return 1;
160 #else
161         struct rlimit rl;
162         if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
163                 return -1;
164         }
165         if (original_dtablesize.rlim_cur == 0) {
166                 original_dtablesize = rl;
167         }
168         if (rl.rlim_cur < rl.rlim_max) {
169                 rl.rlim_cur = rl.rlim_max;
170                 return setrlimit(RLIMIT_NOFILE, &rl);
171         }
172         return 0;
173 #endif
174 }
175
176 int
177 _tt_restoredtablesize(void)
178 {
179 #if defined(_AIX)
180         return 1;
181 #else
182         if (original_dtablesize.rlim_cur == 0) {
183                 return 0;
184         } else {
185                 return setrlimit(RLIMIT_NOFILE, &original_dtablesize);
186         }
187 #endif
188 }
189
190
191 long
192 _tt_gethostid(void)
193 {
194         long _hostid;
195 #if defined(OPT_SYSINFO)
196         {
197                 char            serial_num[40];
198
199                 if (sysinfo(SI_HW_SERIAL, serial_num, 40) > 0) {
200                         sscanf(serial_num, "%12lx", &_hostid);
201                 }
202         }
203 #elif defined(hpux) || defined(_AIX)
204         struct utsname uts_name;
205         
206         uname(&uts_name);
207 #       if defined(_AIX)
208                 _hostid = atol(uts_name.machine);
209 #       else
210                 _hostid = atol(uts_name.idnumber);
211 #       endif
212 #else
213         _hostid = gethostid();
214 #endif
215         return _hostid;
216 }
217
218 /*
219  * _tt_sigset sets up a signal handler in such a way that the handler
220  * is *not* unregistered when the signal handler is entered.  If
221  * returns 0 if an error occurs, else 1, and leaves errno set according
222  * to the underlying system call (sigaction, signal, sigset.)
223  */
224 int
225 _tt_sigset(
226         int     sig,
227         SIG_PF  handler )
228 {
229 #if defined(OPT_POSIX_SIGNAL)
230 /* 
231  * There seems to be some controversy over the type of sa_handler in
232  * C++ programs.  Everybody\'s man page seems to say it is of type
233  * "void (*)()", and that\'s what Solaris does, and I think that\'s what
234  * POSIX says, but both HP and IBM define it as the arguably much more
235  * useful "void (*)(int)", a/k/a SIG_PF.
236  * 
237  * [4 Apr 95] Solaris 2.5 has switched to use void (*)(int), which
238  * is nice for the long run but causes us some short-run problems
239  * as we want this level of the source to compile both on
240  * Solaris 2.4 and Solaris 2.5 for a while. To solve this, we use
241  * the "sa_sigaction" element of the sigaction structure, which is the
242  * three-argument flavor of the function pointer.  This is, strictly, 
243  * a lie, but it's safe since our signal handlers never look at the
244  * arguments anyway.  sa_sigaction is, fortunately, the same on all
245  * Solaris versions.
246  * Once the requirement to compile on Solaris 2.4 goes away, we can
247  * simply remove the OPT_BUG_SUNOS_5 ifdefs here.
248  */
249         struct sigaction act;
250 #if defined(OPT_BUG_SUNOS_5)    
251         act.sa_sigaction = (void (*)(int, siginfo_t *, void *)) handler;
252 #else
253         act.sa_handler = handler;
254 #endif  
255         sigemptyset(&act.sa_mask);
256         act.sa_flags = 0;
257         return 0==sigaction(sig, &act, NULL);
258 #elif defined(OPT_BSD_SIGNAL)
259         return SIG_ERR!=signal(sig, handler);
260 #else
261         return SIG_ERR!=sigset(sig, handler);
262 #endif
263 }
264
265 /*
266  * _tt_putenv - putenv()s a buffer containing "variable=value"
267  * On success, returns the malloc()ed buffer that was passed to putenv().
268  * On failure, returns 0.
269  *
270  * Note: the returned buffer becomes a storage leak after this or any
271  * other form of putenv() replaces variable in the environment.
272  */
273 char *
274 _tt_putenv(
275         const char *variable,
276         const char *value
277 )
278 {
279         if (variable == 0) {
280                 return 0;
281         }
282         if (value == 0) {
283                 value = "";
284         }
285         char *buf = (char *)malloc( strlen(variable) + strlen(value) + 2 );
286         if (buf == 0) {
287                 return 0;
288         }
289         sprintf( buf, "%s=%s", variable, value );
290         if (putenv( buf ) != 0) {
291                 return 0;
292         } else {
293                 return buf;
294         }
295 }
296
297 // prefix passed to _tt_openlog()
298 static _Tt_string *_tt_syslog_prefix = 0;
299
300 // prefix if _tt_openlog() has never been called
301 static _Tt_string *_tt_syslog_default_prefix = 0;
302
303 void
304 _tt_openlog(
305         const char     *prefix,
306         int             logopt,
307         int             facility
308 )
309 {
310         if (_tt_syslog_prefix == 0) {
311                 _tt_syslog_prefix = new _Tt_string;
312         }
313         //
314         // Save the prefix, for when we write the prefix ourselves
315         // instead of letting syslog() do it
316         //
317         *_tt_syslog_prefix = prefix;
318         if (logopt & LOG_PID) {
319                 *_tt_syslog_prefix =
320                         _tt_syslog_prefix->cat("[").cat( getpid() ).cat("]");
321         }
322         *_tt_syslog_prefix = _tt_syslog_prefix->cat(": ");
323         openlog( prefix, logopt, facility );
324 }
325
326 void
327 _tt_vsyslog(
328         FILE           *sink,
329         int             priority,
330         const char     *format,
331         va_list         args
332 )
333 {
334         // XXX also log to ~/.dt/errorlog
335         if (_tt_global && _tt_global->silent) {
336                 return;
337         }
338         _Tt_string _format( format );
339         if (   (_tt_syslog_default_prefix == 0)
340             && (_tt_syslog_prefix == 0))
341         {
342                 //
343                 // Only initialize default prefix if openlog() is uncalled
344                 //
345                 _tt_syslog_default_prefix = new _Tt_string( "libtt[" );
346                 *_tt_syslog_default_prefix =
347                         _tt_syslog_default_prefix->cat( getpid() ).cat( "]: " );
348         }
349         if ((_tt_syslog_prefix == 0) && (_tt_syslog_default_prefix != 0)) {
350                 //
351                 // libtt cannot presume to call openlog(),
352                 // so we add our own prefix when openlog() is uncalled
353                 //
354                 _format = _tt_syslog_default_prefix->cat( _format );
355         }
356         if (sink != 0) {
357                 if (_tt_syslog_prefix != 0) {
358                         _tt_syslog_prefix->print( sink );
359                 }
360                 // XXX We do not handle %%m.
361                 _format = _format.replace( "%m", strerror( errno ) );
362                 vfprintf( sink, _format, args );
363                 fputc( '\n', sink );
364                 fflush( sink );
365                 return;
366         }
367
368 #if defined(OPT_BUG_AIX) || defined(OPT_BUG_HPUX)
369         char buf[5000];
370         vsprintf( buf, _format, args );
371         syslog( priority, buf );
372 #else
373         vsyslog( priority, _format, args );
374 #endif
375 }
376
377 void
378 _tt_syslog(
379         FILE           *sink,
380         int             priority,
381         const char     *format,
382         ...
383 )
384 {
385         va_list args;
386
387         va_start( args, format );
388         _tt_vsyslog( sink, priority, format, args );
389         va_end( args );
390 }
391
392
393 //
394 // _tt_get_first_set_env_var - getenvs i_num_names char*s in the environment, and returns 
395 // the value of the first one found with a non-null value, or NULL if all have no value.
396 // The check is done from left to right across the supplied names.
397 // e.g. _tt_get_first_set_env_var (2, "FOO", "BAR") is functionally equivalent to 
398 // getenv("FOO") ? getenv("FOO") : getenv("BAR");
399 //
400
401 char* _tt_get_first_set_env_var (int i_num_names, ...) {
402     
403     // set up for variable number of arguments
404     va_list p_var;
405     va_start(p_var, i_num_names);
406     
407     char* pc_name_to_check;  // name of the environment var we're currently looking for
408     char* pc_value = NULL;   // value of environment var we're currently looking for
409     int i_index;             // indexes through each of the names supplied
410     
411     // check each of the names in turn
412     for (i_index = 0; i_index < i_num_names; i_index++) {
413         
414         // get the next name to check
415         pc_name_to_check = va_arg(p_var, char*);
416         
417         if (!pc_name_to_check)  // ignore any null names
418             continue;
419         
420         // get the environment value (if any)
421         pc_value = getenv(pc_name_to_check);
422         
423         if (pc_value) // we found one with a value
424             break;
425     }
426     
427     // clean up var args
428     va_end(p_var); 
429     
430     // return the value
431     return pc_value;
432 }
433
434
435 // _tt_put_all_env_var - sets i_num_names char*s in the environment, to pc_val, using _tt_putenv.
436 // NOTE: xxx see the _tt_putenv comments about memory leakage.
437 // _tt_putenv are processed from left to right across the supplied names.  If any
438 // _tt_putenv fails, putenv'ing stops.  The number of successful putenv's is returned
439 // e.g. _tt_put_all_env_var (2, "HELLO", "FOO", "BAR") is functionally equivalent to 
440 // _tt_putenv("FOO", "HELLO") ? 0 : (_tt_putenv("BAR", "HELLO") ? 1 : 2);
441
442 int _tt_put_all_env_var (int i_num_names, const char* pc_val, ...) {
443     
444     // set up for variable number of arguments
445     va_list p_var;
446     va_start(p_var, pc_val);
447     
448     char* pc_name_to_set;  // name of the environment var we're currently looking for
449     char* pc_buff;         // value of _tt_putenv call
450     int i_index;           // indexes through each of the names supplied
451     
452     // check each of the names in turn
453     for (i_index = 0; i_index < i_num_names; i_index++) {
454         
455         // get the next name to check
456         pc_name_to_set = va_arg(p_var, char*);
457         
458         if (!pc_name_to_set)  // ignore any null names
459             continue;
460         
461         // set the environment value (if any)
462         pc_buff = _tt_putenv(pc_name_to_set, pc_val);
463         
464         if (!pc_buff) // we had a problem
465             break;
466     }
467     
468     // clean up var args
469     va_end(p_var); 
470     
471     // return the value
472     return i_index;
473 }
474