mirror of
https://github.com/IanDarwin/OpenLookCDROM.git
synced 2026-01-21 18:25:08 +00:00
2212 lines
78 KiB
Plaintext
2212 lines
78 KiB
Plaintext
From: meyer@frostbite-falls.uoregon.edu (David M. Meyer 503/346-1747)
|
|
Newsgroups: comp.unix.solaris,comp.answers,news.answers
|
|
Subject: Solaris 2 Porting FAQ
|
|
Date: 02 May 1995 11:58:08 GMT
|
|
Organization: University Network Services, University of Oregon, Eugene, OR
|
|
97403
|
|
Lines: 2194
|
|
Approved: news-answers-request@MIT.Edu
|
|
Distribution: world
|
|
Message-ID: <MEYER.95May2045808@frostbite-falls.uoregon.edu>
|
|
Reply-To: meyer@ns.uoregon.edu (David M. Meyer 503/346-1747)
|
|
NNTP-Posting-Host: frostbite-falls.uoregon.edu
|
|
Summary: This posting contains a list of Frequently Asked
|
|
Questions (and their answers) about porting BSD
|
|
applications to ANSI/SVID/SVR4 systems (in general) and
|
|
Solaris 2 (in particular).
|
|
|
|
|
|
Archive-name: Solaris2/porting-FAQ
|
|
Last-modified: Monday, May 01, 1995
|
|
Version: 2.23
|
|
|
|
Solaris 2 Porting FAQ
|
|
[Last modified: 01 May 1995]
|
|
|
|
This article contains the answers to some Frequently Asked
|
|
Questions (FAQ) often seen in comp.unix.solaris that relate to
|
|
porting BSD/Solaris 1 applications to Solaris 2. Over the first
|
|
few days of its existence, it has evolved into a more general
|
|
discussion about portability among Unix systems, especially as it
|
|
relates to BSD, ANSI, POSIX, and SVID compliant systems. It is
|
|
hoped that this document will help reduce volume in this
|
|
newsgroup and to provide hard-to-find information of general
|
|
interest.
|
|
|
|
Please redistribute this article!
|
|
|
|
This FAQ is maintained by David Meyer (meyer@ns.uoregon.edu).
|
|
Send updates and corrections to me at this address. It would
|
|
help if the subject line contained the phrase "FAQ".
|
|
|
|
This article includes answers to the following questions. Ones
|
|
marked with a + indicate questions new to this issue; those with
|
|
changes of content since the last issue are marked by *:
|
|
|
|
0) Which preprocessor symbols to use?
|
|
1) Some Include File Issues
|
|
2) Libraries
|
|
3)* Possible ANSI/POSIX/SVR4 replacements for some popular BSD functions
|
|
4) Signal Primer
|
|
5) Waiting for Children to Exit
|
|
6) Dealing with Shadow Password Files
|
|
7) Some Compatibility Problems
|
|
8) Other Resources
|
|
|
|
-----------------------------------------------------------------------------
|
|
0) TOPIC: Which preprocessor symbols to use?
|
|
|
|
[Last modified: 11 October 93]
|
|
|
|
[Editor's Note: This section began life as a Solaris 1 and
|
|
Solaris 2 centric discussion. However, it has grown into a more
|
|
generalized portability discussion. I believe that this is a
|
|
useful discussion, but it appears that contrasting styles,
|
|
preferences, and requirements will make consensus difficult. DM]
|
|
|
|
Answer: This is a difficult and controversial question.
|
|
|
|
In order to understand the following discussion, we need to be
|
|
aware of the following standards:
|
|
|
|
ANSI C (ANSI X3J11)
|
|
|
|
This is the standard C definition, originally adopted as
|
|
American National Standard X3.159-1989 and has since been
|
|
adopted as international standard ISO/IEC 9899:1990.
|
|
|
|
|
|
POSIX.1 (IEEE 1003.1-1990)
|
|
|
|
POSIX.1, the Portable Operating System Interface for
|
|
Computer Environments, is a system level API that deals
|
|
with the function and format of system calls and
|
|
utilities such as signal handling.
|
|
|
|
SVID3
|
|
|
|
SVID3, the System V Interface Definition Issue 3, is is
|
|
fully compliant with POSIX.1, and is a arguably subset of
|
|
the SVR4 system API. For example, SVID3 doesn't have
|
|
"-ldl", but many people consider it of the SVR4 API. That
|
|
is, a system could be SVID3-compliant without necessarily
|
|
being an SVR4 system.
|
|
|
|
XPG
|
|
|
|
XPG, X/Open Company Ltd's X/Open Portability Guide, is a
|
|
broad document which covers a great number of areas,
|
|
including operating systems and programming languages,
|
|
system interfaces, and internetworking. The latest
|
|
version, XPG4, groups these components into "profiles",
|
|
which are packaged together according to market needs.
|
|
|
|
|
|
Two additional standards are relevant for Suns:
|
|
|
|
SCD 2.0 and x86 ABIs
|
|
|
|
SCD 2.0 is the SPARC Compliance Definition 2.0. The SCD
|
|
has two components: On the hardware side,
|
|
|
|
(i). System Compliance Test verifies that the hardware
|
|
and operating system successfully emulates what
|
|
Sun is doing. It covers low level system issues
|
|
such as alignment, and linking and loading.
|
|
|
|
(ii). The SPARC Application Verifier tests software to
|
|
be sure that it runs on SCD hardware.
|
|
|
|
|
|
As an example of subtle differences that exist between the BSD
|
|
interface and SVID/POSIX standards, consider the BSD mktemp(3)
|
|
call. The SunOS 4.1 mktemp() replaced the trailing X characters
|
|
with the letter (e.g., X) and the current process ID. The SVID
|
|
and SVR4 versions specify only that the six trailing Xs be
|
|
replaced with a character string that can be used to create a
|
|
unique filename, and does not depend on the specific name of the
|
|
file. Thus, the BSD and SVR4/SVID3 versions are only
|
|
semantically equivalent in the case where only the application
|
|
cares that the filename is unique.
|
|
|
|
Now, the basic philosophical question of which preprocessor
|
|
contstucts to use here would appear to revolve around the
|
|
following choices:
|
|
|
|
(i). Use a high level, large grained standard
|
|
definition (e.g., _POSIX_SOURCE). In this case,
|
|
features are implicitly defined. One problem with
|
|
such definitions is that they may cause other
|
|
useful functions to become unavailable. However,
|
|
there are several such definitions in common use.
|
|
For operating systems, we have
|
|
|
|
SVR4
|
|
SYSV
|
|
BSD
|
|
OSF1
|
|
|
|
to name a few. For standards, we are mainly
|
|
interested interested symbols such as
|
|
|
|
__STDC__
|
|
_POSIX_SOURCE
|
|
_XOPEN_SOURCE
|
|
|
|
|
|
This method is not without pitfalls. For
|
|
example, the Sun SC2.0.1 compiler defines
|
|
__STDC__ as 0 when compiling in transition mode
|
|
(-Xt), only setting it to 1 when the strict ANSI
|
|
mode (-Xc) is used. The expression
|
|
|
|
#if (__STDC__ - 0 == 0)
|
|
|
|
can be used to recognize strict v. transition
|
|
ANSI modes. On Solaris 2, if you compile with
|
|
-Xc, you will lose all non-ANSI functionality.
|
|
However, you can define _POSIX_SOURCE or
|
|
_XOPEN_SOURCE to get a POSIX or XOPEN
|
|
environment.
|
|
|
|
If you use _POSIX_SOURCE, .eg.,
|
|
|
|
#define _POSIX_SOURCE 1
|
|
|
|
then all symbols not defined by Standard C or the
|
|
POSIX standard will be hidden (except those with
|
|
leading underscores). If you wish to use
|
|
_POSIX_SOURCE, be sure to define it before
|
|
including any standard header files, and avoid
|
|
name clashes by not defining any symbols that
|
|
begin with "_" (Similarly, note that almost all
|
|
names beginning with "E" are reserved by
|
|
errno.h, and many names prefixed by "va_"
|
|
reserved by stadarg.h).
|
|
|
|
One more note on _POSIX_SOURCE: SunOS 5.3 has
|
|
introduced the new header file <sys/feature_tests.h>.
|
|
This file is included in all files which have
|
|
_POSIX_SOURCE dependancies.
|
|
|
|
A new symbol, _POSIX_C_SOURCE was introduced in POSIX.2
|
|
(V1 P720, L51) as a mechanism to enable POSIX.1 and
|
|
POSIX.2 symbols. Its values are as follows:
|
|
|
|
/*
|
|
* Values of _POSIX_C_SOURCE
|
|
*
|
|
* undefined not a POSIX compilation
|
|
* 1 POSIX.1-1990 compilation
|
|
* 2 POSIX.2-1992 compilation
|
|
* 1993xxL POSIX.4-1993 compilation
|
|
*/
|
|
|
|
|
|
This means that POSIX.2 says that a value of 1 = POSIX.1
|
|
and a value of 2 = POSIX.1 & POSIX.2. The idea here is
|
|
to provide a single control point over the POSIX namespace,
|
|
rather than having to edit each file individually.
|
|
|
|
Another potential portability pitfall is the
|
|
__svr4__ feature defined by the FSF (gcc). If you
|
|
depend on __svr4__, you may lose portability.
|
|
gcc also defines sun if you don't give the -ansi
|
|
argument. If you use -ansi, then sun is not
|
|
defined and __sun__ is.
|
|
|
|
Finally, complexity may arise surrounding a
|
|
feature which may be part of some vendor's
|
|
version of some system Y, but may also exist in
|
|
non-Y compliant systems. Consider, for example,
|
|
shadow passwording. Systems conforming to the
|
|
latest SVID (e.g., SVR4) have shadow.h, but there
|
|
are many systems that have shadow.h without
|
|
conforming to the SVID.
|
|
|
|
So, in general, for code that uses a STD_FEATURE and
|
|
runs on systems W, Y, and Z, you are left with
|
|
something that may look like
|
|
|
|
#if defined(W) ||
|
|
(defined(Y) && _Y_VERSION_ > 3) ||
|
|
(defined(Z) || defined(__Z__))
|
|
#include <STD_FEATURE.h>
|
|
#endif
|
|
|
|
[W, Y, Z are things like SVR4, AIX, NeXT, BSD,
|
|
and so on. STD_FEATURE.h is something like shadow.h]
|
|
|
|
This example exposes two problems the large
|
|
grained method. First, it forces one to keep
|
|
track of exactly which vendors supply
|
|
<STD_FEATURE.h>. Second, the complexity of the
|
|
preprocessor expressions may be a serious
|
|
consideration, since their complexity is
|
|
something like
|
|
|
|
O(n*m) where
|
|
|
|
n = the number of standard features, and
|
|
m = number of vendors/systems
|
|
|
|
|
|
(ii). Define new fine-grained feature tests (e.g.,
|
|
HAVE_POSIX_SIGNALS, or HAVE_SHADOW_H) for
|
|
features of interest. Such fine-grained features
|
|
could be used in conjunction with large grained
|
|
definitions. An nice example of using feature
|
|
definitions is the GNU configure program. It
|
|
uses, for example, the features HAVE_BCOPY and
|
|
HAVE_MEMSET to enable either the bcopy (BSD) or
|
|
memset (ANSI) functions.
|
|
|
|
Feature testing has the advantage of being useful
|
|
for automatic configuration with programs such as
|
|
GNU configure. GNU configure outputs statements
|
|
of the form
|
|
|
|
|
|
#define HAVE_aaaa
|
|
#define HAVE_bbbb
|
|
#define HAVE_cccc
|
|
....
|
|
|
|
Another way to generate a feature set is by
|
|
using the symbol defining the system, e.g.,
|
|
|
|
#ifdef SVR4
|
|
#define HAVE_aaaa
|
|
#define HAVE_bbbb
|
|
#define HAVE_cccc
|
|
....
|
|
|
|
#endif
|
|
#ifdef BSD43
|
|
#define HAVE_yyyy
|
|
...
|
|
#endif
|
|
#ifdef NEWTHING
|
|
#define HAVE_zzzz
|
|
...
|
|
#endif
|
|
|
|
Feature testing also helps to avoid constructs
|
|
such as
|
|
|
|
#if defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE)
|
|
|
|
[Editor's Note: Finally, an observation: The real
|
|
issue here appears to be how many of these
|
|
"features" are migrating to the standard
|
|
operating systems and interfaces, and how many
|
|
vendors are implementing these standards. In
|
|
general, some people feel that feature testing
|
|
improves portability (and readability), and
|
|
others believe that the feature testing style
|
|
decreases portability and readability. DM]
|
|
|
|
|
|
(iii). Use some part of the feature's definition itself
|
|
to enable the feature, for example
|
|
|
|
#ifdef _IOLBF
|
|
setvbuf(stderr, NULL, _IOLBF, 0);
|
|
#else
|
|
setlinebuf(stderr);
|
|
#endif /* _IOLBF */
|
|
|
|
Note that in this case, another, possibly better
|
|
option is (consider the case in which some vendor
|
|
has inadvertently defined _IOLBF for some other
|
|
purpose):
|
|
|
|
#ifdef __STDC__
|
|
setvbuf(stderr, NULL, _IOLBF, 0);
|
|
#else
|
|
setlinebuf(stderr);
|
|
#endif /* __STDC__ */
|
|
|
|
since setvbuf is required by Standard C.
|
|
|
|
|
|
|
|
Finally, some people have suggested the use of
|
|
expressions like
|
|
|
|
#if defined(sun) && defined(__svr4__)
|
|
<Solaris 2 centric code>
|
|
#else
|
|
...
|
|
#endif
|
|
|
|
|
|
As noted above, the __svr4__ feature is defined by the
|
|
FSF (gcc). If you depend on __svr4__, you may lose
|
|
portability. gcc also defines sun if you don't give the
|
|
-ansi argument. If you use -ansi, then sun is not
|
|
defined and __sun__ is. The implication here is that
|
|
depending on symbols defined by a given compiler can
|
|
reduce portability.
|
|
|
|
In general, such a construct should be used if and only if
|
|
the code in question cannot be covered by some standard
|
|
(e.g., SVR4, _POSIX_SOURCE, etc.). Note that it is also
|
|
compiler specific.
|
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
1) TOPIC: Include File Issues
|
|
|
|
[Last modified: 19 August 93]
|
|
|
|
The first and apparently most common problem is that
|
|
/usr/include/strings.h is not ANSI compliant, and as such does not
|
|
exist on Solaris 2 (or SVR4). It should be replaced by
|
|
/usr/include/string.h, e.g. (following GNU feature definition
|
|
conventions)
|
|
|
|
#if HAVE_STRING_H || defined(STDC_HEADERS)
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
#if defined(STDC_HEADERS)
|
|
#include <stdlib.h>
|
|
#endif /* HAVE_STRING_H */
|
|
|
|
while ANSI-C requires the name be string.h, one might
|
|
define this as
|
|
|
|
#ifdef __STDC__
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif /* __STDC__ */
|
|
|
|
However, this again neglects the case in which the vendor
|
|
provides string.h in a non-ANSI environment.
|
|
|
|
|
|
Another thing to watch is for the symbols O_CREAT, O_TRUNC, and
|
|
O_EXCL being undefined. On BSD systems, these are defined in
|
|
<sys/file.h>. On Solaris 1 systems (beginning with SunOS 4.0) ,
|
|
these are defined in <sys/fnctlcom.h> (which is included in
|
|
<sys/file.h>). On a POSIX compliant system, these symbols are
|
|
defined in <fcntl.h>, which is not included in <sys/file.h>.
|
|
Since <fcntl.h> is defined on SunOS 4.1.x, replacing <sys/file.h>
|
|
with <fcntl.h> works for both SunOS 4.1.x and SVR4. See, for
|
|
example, section 5.3.1.1 of the POSIX spec.
|
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
2) TOPIC: Libraries
|
|
|
|
[Last modified: 12 Feburary 94]
|
|
|
|
Network Libraries:
|
|
|
|
Many of the network functions and definitions that were present
|
|
in the BSD libc are now in libnsl.so and libsocket.so. Thus
|
|
networking code will generally need to be linked with -lsocket
|
|
-lnsl. Since libsocket.so requires libnsl.so (it is NEEDED), you must
|
|
specify them in this order. Note that you need libnsl.so for functions
|
|
like gethostbyname (see gethostbyname note below). Incidently, you can
|
|
look at selected parts of an object file using dump(1), e.g.,
|
|
|
|
% dump -Lv /usr/lib/libsocket.so
|
|
|
|
/usr/lib/libsocket.so:
|
|
|
|
**** DYNAMIC SECTION INFORMATION ****
|
|
.dynamic :
|
|
[INDEX] Tag Value
|
|
[1] NEEDED libnsl.so.1
|
|
[2] INIT 0x3174
|
|
|
|
[...]
|
|
|
|
Regular Expressions
|
|
|
|
Another problem frequently encountered is that the regexp
|
|
functions (see regexpr(3G)) are not defined in libc. On Solaris
|
|
2, you must link with libgen.a (-lgen) in order to get these
|
|
definitions. See Intro(3) for a more complete discussion.
|
|
|
|
Name List (nlist)
|
|
|
|
You must link with libelf.a (-lelf) to get the nlist(3E)
|
|
definition.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
3)* TOPIC: Possible ANSI/POSIX/SVR4 replacements for some popular
|
|
BSD functions
|
|
|
|
[Last modified: 01 May 1995]
|
|
|
|
[Editor's Note: Once again, this section began life a SunOS 4.1.x
|
|
and SunOS 5.x centric discussion. It too has grown into a
|
|
discussion dealing with general portability for BSD to other
|
|
standards. DM]
|
|
|
|
Problems finding functions that were defined in the BSD libc.a is
|
|
one of the most frequently asked porting questions. The following
|
|
table and code fragments suggest substitutes for some common BSD
|
|
constructs (more complete lists can be found in some of the texts
|
|
listed in section 7 below).
|
|
|
|
In addtion to the possibilites listed below, many people have
|
|
created compatability libraries using GNU autoconfigure. An
|
|
example of this is the "generic" libary from Dan Stromberg
|
|
(strombrg@hydra.acs.uci.edu). It can be found on
|
|
ftp.uci.edu:/pub/generic/generic.tar.gz.
|
|
|
|
|
|
BSD Possibilities Standards/Notes
|
|
============================================================================
|
|
srandom(seed) srand(seed) ANSI-C (Also, some older UNIX)
|
|
srand48(seed) SVR4
|
|
|
|
non-ANSI signal() sigset() SVR4 (systems calls not
|
|
(e.g., SunOS) restarted, but bytes r/w
|
|
returned, else EINTR)
|
|
sigaction POSIX (but extensible by
|
|
implementation)
|
|
|
|
sigvec sigaction POSIX
|
|
sigblock sigprocmask POSIX
|
|
sigset(.., SIG_HOLD)
|
|
sighold SVR4
|
|
sigsetmask sigprocmask POSIX
|
|
sigset/sigrelse SVR4
|
|
|
|
sigpause sigsuspend POSIX
|
|
|
|
setjmp sigsetjmp POSIX
|
|
longjmp siglongjmp POSIX
|
|
|
|
statfs statvfs SVR4
|
|
|
|
bcopy memmove ANSI-C (BSD bcopy() handles
|
|
overlapping areas
|
|
correctly, as does
|
|
memmove, but not memcpy)
|
|
|
|
bzero memset ANSI-C
|
|
|
|
index strchr ANSI-C
|
|
rindex strrchr ANSI-C
|
|
|
|
getwd getcwd POSIX
|
|
|
|
getrusage open,ioctl The getrusage information
|
|
(and a whole lot more) can be
|
|
found in the prusage structure.
|
|
Use the PIOCUSAGE ioctl. See
|
|
the example below and the
|
|
proc(4) man page for detail.
|
|
|
|
|
|
gethostname sysinfo(SI_HOSTNAME,..) SVR4 See sysinfo(2) for
|
|
many other possible
|
|
values
|
|
|
|
getdtablesize sysconf(_SC_OPEN_MAX) POSIX See sysconf(3C) for
|
|
many other values
|
|
available via sysconf.
|
|
|
|
strptime See code from Kevin Ruddy
|
|
below
|
|
|
|
timelocal mktime
|
|
|
|
wait3 w/o rusage waitpid POSIX
|
|
wait3 waitid SVR4
|
|
wait3 See J"org Schilling's wait3
|
|
emulation code below.
|
|
|
|
usleep nanosleep POSIX See nanosleep(3R) on
|
|
Solaris 2.3 (see libposix4.a)
|
|
For a Solaris 2.[0-2], see the
|
|
example below.
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------------------
|
|
|
|
Some Well-Traveled Macros
|
|
-------------------------
|
|
|
|
#define bcopy(src,dest,len) (memmove((dest), (src), (len)))
|
|
#define bzero(dest,len) (memset((dest), (char)0, (len)))
|
|
#define bcmp(b1,b2,n) (memcmp((b1),(b2),(n)))
|
|
#define index(s,c) strchr((s),(c))
|
|
#define rindex(s,c) strrchr((s),(c))
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
#define MAX(a, b) ((a) < (b) ? (b) : (a))
|
|
#ifdef MAXPATHLEN
|
|
#define getwd(x) getcwd((x), MAXPATHLEN)
|
|
#endif /* MAXPATHLEN */
|
|
define setlinebuf(fp) setvbuf(fp, NULL, _IOLBF, 0);
|
|
|
|
|
|
Timing Problems
|
|
---------------
|
|
|
|
POSIX defines the <sys/times.h> function for subsecond
|
|
timing. Sun seems to provide about 1/60 second accuracy.
|
|
|
|
#include <stdio.h>
|
|
#include <sys/times.h> /* for struct tms and times() */
|
|
#include <time.h> /* for CLK_TCK value */
|
|
|
|
int main(void) {
|
|
struct tms tms_start, tms_finish; /* user and system time */
|
|
clock_t start, finish; /* real time */
|
|
start = times( &tms_start );
|
|
/* ... do something ... */
|
|
finish = times( &tms_finish );
|
|
printf("(in seconds) %f real, %f system, %f user\n",
|
|
(finish-start) / (double)CLK_TCK,
|
|
(tms_finish.tms_stime-tms_start.tms_stime) / (double)CLK_TCK,
|
|
(tms_finish.tms_utime-tms_start.tms_utime) / (double)CLK_TCK);
|
|
return 0;
|
|
}
|
|
|
|
You might want to divide CLK_TCK by 1000.0 to get more
|
|
precise millisecond values. times() returns -1 if it
|
|
cannot provide timing information.
|
|
|
|
While Solaris 2 conforms to POSIX, SunOS 4.1 defines
|
|
times() as returning a flag instead of elapsed real time.
|
|
You can use ftime() to get elapsed real time:
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h> /* for time_t */
|
|
#include <sys/timeb.h> /* for ftime() and struct timeb */
|
|
|
|
int main(void) {
|
|
struct timeb start, finish;
|
|
double real_secs;
|
|
ftime( &start );
|
|
/* ... do something ... */
|
|
ftime( &finish );
|
|
real_secs = finish.time - start.time;
|
|
if ( finish.millitm < start.millitm )
|
|
real_secs = (real_secs-1) +
|
|
(1000+start.millitm-finish.millitm)/1000.0;
|
|
else
|
|
real_secs = (finish.millitm-start.millitm)/1000.0;
|
|
printf( "That took %f real seconds.", real_secs );
|
|
return 0;
|
|
}
|
|
|
|
The ANSI C function clock() can also be used for timing.
|
|
It returns elased "processor" time, which is equivalent
|
|
to system+user time. While it also returns a clock_t
|
|
value, you must divide the difference between to calls to
|
|
clock() by CLOCKS_PER_SEC, *not* CLK_TCK. The values are
|
|
different by orders of magnitude. SunOS 4.1 doesn't seem
|
|
to provide CLOCKS_PER_SEC or CLK_TCK in <time.h>. Try
|
|
10000000 and 60, respectively.
|
|
|
|
|
|
|
|
Compatibility Functions
|
|
-----------------------
|
|
|
|
/*
|
|
* getrusage --
|
|
*/
|
|
|
|
#include <sys/resource.h>
|
|
#ifndef RUSAGE_SELF
|
|
#include <sys/procfs.h>
|
|
#endif
|
|
|
|
#ifdef PIOCUSAGE
|
|
int fd;
|
|
char proc[SOMETHING];
|
|
prusage_t prusage;
|
|
|
|
sprintf(proc,"/proc/%d", getpid());
|
|
if ((fd = open(proc,O_RDONLY)) == -1) {
|
|
perror("open");
|
|
....
|
|
}
|
|
if (ioctl(fd, PIOCUSAGE, &prusage) == -1) {
|
|
perror("ioctl");
|
|
...
|
|
}
|
|
....
|
|
#else /* Again, assume BSD */
|
|
if (getrusage(RUSAGE_SELF, &rusage) == -1) {
|
|
perror("getrusage");
|
|
....
|
|
}
|
|
....
|
|
#endif /* PIOCUSAGE */
|
|
|
|
|
|
|
|
/*
|
|
* setlinebuf --
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
setvbuf(stderr, NULL, _IOLBF, 0);
|
|
#else
|
|
setlinebuf(stderr);
|
|
#endif /* __STDC__ */
|
|
|
|
|
|
/*
|
|
* gethostid
|
|
*
|
|
* This example has a combination of high-level
|
|
* (SVR4) and (SI_HW_SERIAL) feature declarations.
|
|
*/
|
|
|
|
#if defined(SVR4) && defined(SI_HW_SERIAL)
|
|
long gethostid() {
|
|
|
|
char buf[128];
|
|
|
|
if (sysinfo(SI_HW_SERIAL, buf, 128) == -1) {
|
|
perror("sysinfo");
|
|
exit(1);
|
|
}
|
|
return(strtoul(buf,NULL,0));
|
|
}
|
|
#endif /* SVR4 && SI_HW_SERIAL */
|
|
|
|
|
|
/*
|
|
* getdtablesize --
|
|
*
|
|
* Several possibilites here. Note that while one
|
|
* can emulate getdtablesize with getrlimit on SVR4
|
|
* or 4.3BSD (or later), these systems should be
|
|
* POSIX.1 compliant, so sysconf is preferred.
|
|
*
|
|
*/
|
|
|
|
#ifdef _SC_OPEN_MAX /* POSIX -- preferred */
|
|
if ((tableSize = sysconf(_SC_OPEN_MAX)) == -1) {
|
|
perror("sysconf");
|
|
...
|
|
}
|
|
#elif RLIMIT_NOFILE /* who is non POSIX but has this? */
|
|
if (getrlimit(RLIMIT_NOFILE, &rlimit) == -1) {
|
|
perror("getrlimit");
|
|
exit(1);
|
|
}
|
|
tableSize = rlimit.rlim_max;
|
|
#else /* assume old BSD type */
|
|
tableSize = getdtablesize();
|
|
#endif
|
|
|
|
|
|
------------------
|
|
|
|
/*
|
|
* gethostname --
|
|
*
|
|
*/
|
|
|
|
#ifdef SVR4
|
|
#include <sys/systeminfo.h>
|
|
#endif /* SVR4 */
|
|
|
|
....
|
|
|
|
char buf[MAXHOSTNAME]
|
|
|
|
#ifdef SVR4
|
|
if (sysinfo(SI_HOSTNAME, buf, sizeof(buf)) <0) {
|
|
perror("SI_HOSTNAME");
|
|
exit(BAD);
|
|
}
|
|
#else /* Assume BSD */
|
|
if (gethostname(buf, sizeof(buf)) < 0) {
|
|
perror("gethostname");
|
|
exit(BAD);
|
|
}
|
|
#endif /* SVR4 */
|
|
|
|
/* buf has hostname here... */
|
|
|
|
|
|
/*
|
|
* usleep(delay) --
|
|
*
|
|
* Possible usleep replacement. Delay in microseconds.
|
|
* Another possiblity is to use poll(2). On Solaris
|
|
* 2.x, select is just a wrapper for poll, so you
|
|
* are better off using it directly. If you use,
|
|
* poll, note that it uses millisecond resolution,
|
|
* and is not affected by the O_NDELAY and O_NONBLOCK
|
|
* flags.
|
|
*
|
|
* Note that using nanosleep has portability implications,
|
|
* even across different versions of Solaris 2.x. In
|
|
* particular, only Solaris 2.3 has libposix4, and
|
|
* hence nanosleep. Select (or poll) is a better option if
|
|
* you need portability across those versions.
|
|
*
|
|
* If you define USE_NANOSLEEP, be sure to link with -lposix4
|
|
*
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#ifdef USE_POLL
|
|
#include <stropts.h>
|
|
#include <poll.h>
|
|
#endif /* USE_POLL */
|
|
|
|
int usleep(unsigned long int useconds)
|
|
{
|
|
#ifdef USE_NANOSLEEP
|
|
struct timespec rqtp;
|
|
|
|
rqtp.tv_sec = useconds / (unsigned long) 1000000;
|
|
rqtp.tv_nsec = (useconds % (unsigned long) 1000000) * 1000 ;
|
|
|
|
if (nanosleep(&rqtp, (struct timespec *) NULL) == -1)
|
|
perror("nanosleep");
|
|
return (0);
|
|
|
|
#elif USE_POOL
|
|
struct pollfd unused;
|
|
|
|
if (poll(&unused,0,(useconds/1000)) == -1)
|
|
perror("poll");
|
|
return(0);
|
|
#elif USE_USLEEP
|
|
struct timeval delay;
|
|
|
|
delay.tv_sec = 0;
|
|
delay.tv_usec = useconds;
|
|
if (select(0,
|
|
(fd_set *) NULL,
|
|
(fd_set *) NULL,
|
|
(fd_set *) NULL,
|
|
&delay) == -1)
|
|
perror("select");
|
|
return (0);
|
|
#endif /* USE_NANOSLEEP */
|
|
|
|
|
|
/*
|
|
* tzsetwall --
|
|
*/
|
|
|
|
void tzsetwall()
|
|
{
|
|
unsetenv("TZ");
|
|
tzset();
|
|
}
|
|
|
|
/*
|
|
* gethostybname --
|
|
*
|
|
* The following code was contributed by Casper H.S. Dik
|
|
* to address the following problem:
|
|
*
|
|
* gethostbyname() always returns null in h->aliases.
|
|
* Now, gethostbyX can be replaced its __switch_gethostbyX
|
|
* equivalents. However, these are missing from Solaris 2.3.
|
|
*
|
|
* The _r functions are reentrant. They have a different
|
|
* calling sequence. (The __switch_getXXXbyYYY are called
|
|
* like getXXXbyYYY, the _switch_getXXXbyYYY_r are called
|
|
* like getXXXbyYYY_r)
|
|
*
|
|
* With this bit of knowledge I constructed the code that
|
|
* follows this message. Just plug it in every program
|
|
* that requires gethostbyname to work. (Gethostbyaddr()
|
|
* is added for symmetry).
|
|
*
|
|
* You'll need to link with -lnsl -ldl.
|
|
*
|
|
* It works for Solaris 2.2 and 2.3. (Compiled on 2.3 or
|
|
* 2.2 it will run 2.2 and 2.3)
|
|
*
|
|
* Note that as with __switch* _switch*_r is undocumented
|
|
* and can be changed in the next release.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Proper gethostbyXX function for Solaris 2.0-2.3
|
|
* (and later ?)
|
|
*
|
|
* Fixed in 2.4?
|
|
*
|
|
* You'll need -ldl added to the link command line.
|
|
*
|
|
* Casper Dik (casper@fwi.uva.nl)
|
|
*
|
|
*/
|
|
|
|
#include <netdb.h>
|
|
#include <dlfcn.h>
|
|
|
|
#define HBUFSIZE 4096
|
|
|
|
static void *dlhandle;
|
|
/* The gethostbyXXX function variables. Named after
|
|
* then .so files they appear in. nsw*.so in SunOS 5.2
|
|
* and earlier, nss_*.so in 5.3 */
|
|
static struct hostent *(*nswghba)(const char *, int, int),
|
|
*(*nswghbn)(const char *),
|
|
*(*nss_ghba)(const char *,
|
|
int, int,
|
|
struct hostent *, char *, int, int *),
|
|
*(*nss_ghbn)(const char *,
|
|
struct hostent *, char *, int, int *);
|
|
|
|
static int dlinit(void)
|
|
{
|
|
static int dlstatus = 0; /* 0 = uninited, 1 = inited & ok, -1 = error */
|
|
|
|
if (dlstatus)
|
|
return dlstatus;
|
|
|
|
dlstatus = -1;
|
|
|
|
dlhandle = dlopen(0, RTLD_LAZY);
|
|
|
|
if (dlhandle == 0)
|
|
return dlstatus;
|
|
|
|
/* SunOS 5.0 - 5.2 */
|
|
nswghba = (struct hostent *(*)(const char *, int, int))
|
|
dlsym(dlhandle, "__switch_gethostbyaddr");
|
|
|
|
nswghbn = (struct hostent *(*)(const char *))
|
|
dlsym(dlhandle, "__switch_gethostbyname");
|
|
|
|
/* either both should exist or both should not exist */
|
|
if ((nswghbn == 0) != (nswghba == 0))
|
|
return dlstatus;
|
|
|
|
if (nswghbn)
|
|
return dlstatus = 1;
|
|
|
|
/* SunOS 5.3 - ? */
|
|
nss_ghba = (struct hostent *(*)
|
|
(const char *, int, int, struct hostent *, char *, int , int *))
|
|
dlsym(dlhandle, "_switch_gethostbyaddr_r");
|
|
|
|
nss_ghbn = (struct hostent *(*)
|
|
(const char *, struct hostent *, char *, int , int *))
|
|
dlsym(dlhandle, "_switch_gethostbyname_r");
|
|
|
|
/* these two must exist when we get here */
|
|
if (nss_ghbn != 0 && nss_ghba != 0)
|
|
dlstatus = 1;
|
|
|
|
return dlstatus;
|
|
}
|
|
|
|
struct hostent *
|
|
gethostbyname(const char *name) {
|
|
|
|
static struct hostent hp;
|
|
static char buf[HBUFSIZE];
|
|
|
|
if (dlinit() == -1)
|
|
return 0;
|
|
|
|
if (nswghbn)
|
|
return nswghbn(name);
|
|
else
|
|
return nss_ghbn(name, &hp, buf, sizeof(buf), &h_errno);
|
|
}
|
|
|
|
struct hostent *
|
|
gethostbyaddr(const char *addr, int len, int type) {
|
|
static struct hostent hp;
|
|
static char buf[HBUFSIZE];
|
|
|
|
if (dlinit() == -1)
|
|
return 0;
|
|
|
|
if (nswghba)
|
|
return nswghba(addr, len, type);
|
|
else
|
|
return nss_ghba(addr,
|
|
len, type, &hp, buf, sizeof(buf), &h_errno);
|
|
}
|
|
|
|
|
|
------------------
|
|
wait3
|
|
-----------------
|
|
|
|
This is an alternative to the wait3() implementation from
|
|
/usr/ucblib. It comes from J"org Schilling
|
|
(joerg@schily.isdn.cs.tu-berlin.de js@cs.tu-berlin.de).
|
|
|
|
Some of the rusage fields present in SunOS 4.x are
|
|
missing from the Solaris /usr/ucblib wait3
|
|
implementation. The fields missing from the /usr/ucblib
|
|
wait3 implemenation are:
|
|
|
|
rusage->ru_maxrss
|
|
rusage->ru_ixrss
|
|
rusage->ru_idrss
|
|
rusage->ru_isrss
|
|
|
|
J"org's implementation provides these rusage fields.
|
|
|
|
Some other notes on this J"org's implementation:
|
|
|
|
(i). The wait3() implementation found in /usr/ucblib
|
|
provides only full seconds in the ru_utime and
|
|
ru_stime fields. The usecs are always zeroed.
|
|
J"org's implementation (below) provides clock
|
|
tick resolution (a la' SunOS 4.x).
|
|
|
|
(ii). If the process beeing waited for is setuid and
|
|
the parent is not run by root, the /proc entry
|
|
for the child may not be opened. In these cases
|
|
only time information is available.
|
|
|
|
/* @(#)wait3.c 1.1 95/03/22 Copyr 1995 J. Schilling */
|
|
#ifndef lint
|
|
static char sccsid[] =
|
|
"@(#)wait3.c 1.1 95/03/22 Copyr 1995 J. Schilling";
|
|
#endif lint
|
|
/*
|
|
* Compatibility function for BSD wait3().
|
|
*
|
|
* J"org Schilling (joerg@schily.isdn.cs.tu-berlin.de js@cs.tu-berlin.de)
|
|
*
|
|
* Tries to get rusage information from /proc filesystem.
|
|
* NOTE: since non root processes are not allowed to open suid procs
|
|
* we cannot get complete rusage information in this case.
|
|
*
|
|
* Theory of Operation:
|
|
*
|
|
* On stock SVR4 there is no way to get resource usage information.
|
|
* We may only get times information from siginfo struct:
|
|
*
|
|
* wait3()
|
|
* {
|
|
* call waitid(,,,);
|
|
* if (child is found) {
|
|
* compute times from siginfo and fill in rusage
|
|
* }
|
|
* }
|
|
*
|
|
* Solaris (at least 2.3) has PIOCUSAGE which is guaranteed
|
|
* to work even on zombies:
|
|
*
|
|
* wait3()
|
|
* {
|
|
* call waitid(P_ALL,,,options|WNOWAIT);
|
|
* if (child is found) {
|
|
* compute times from siginfo and fill in rusage
|
|
* if (can get /proc PIOCUSAGE info)
|
|
* fill in rest of rusage from /proc
|
|
* selective call waitid(P_PID, pid,,);
|
|
* }
|
|
*
|
|
* /proc ioctl's that work on zombies:
|
|
* PIOCPSINFO, PIOCGETPR, PIOCUSAGE, PIOCLUSAGE
|
|
*
|
|
*/
|
|
#include <wait.h>
|
|
#ifdef WNOWAIT /* We are on SVR4 */
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/times.h>
|
|
#include <sys/siginfo.h>
|
|
#include <sys/procset.h>
|
|
#include <sys/param.h>
|
|
#include <sys/procfs.h>
|
|
#include "resource.h" /* local version of BSD /usr/include/sys/resource.h */
|
|
|
|
static int wait_prusage(siginfo_t *, int, struct rusage *);
|
|
static int wait_status(int, int);
|
|
static void wait_times(siginfo_t *, struct rusage *);
|
|
|
|
wait3(status, options, rusage)
|
|
int *status;
|
|
int options;
|
|
struct rusage *rusage;
|
|
|
|
{
|
|
siginfo_t info;
|
|
|
|
if (rusage)
|
|
memset((void *)rusage, 0, sizeof(struct rusage));
|
|
memset((void *)&info, 0, sizeof(siginfo_t));
|
|
|
|
/*
|
|
* BSD wait3() only supports WNOHANG & WUNTRACED
|
|
*
|
|
* You may want to modify the next two lines to meet your requirements:
|
|
* 1) options &= (WNOHANG|WUNTRACED);
|
|
* 2a) options |= (WEXITED|WSTOPPED|WTRAPPED);
|
|
* 2b) options |= (WEXITED|WSTOPPED|WTRAPPED|WCONTINUED);
|
|
*
|
|
* If you want BSD compatibility use 1) and 2a)
|
|
* If you want maximum SYSV compatibility remove both lines.
|
|
*/
|
|
options &= (WNOHANG|WUNTRACED);
|
|
options |= (WEXITED|WSTOPPED|WTRAPPED);
|
|
if (waitid(P_ALL, 0, &info, options|WNOWAIT) < 0)
|
|
return (-1);
|
|
|
|
(void) wait_prusage(&info, options, rusage);
|
|
if (status)
|
|
*status = wait_status(info.si_code, info.si_status);
|
|
return (info.si_pid);
|
|
}
|
|
|
|
static int wait_prusage(info, options, rusage)
|
|
siginfo_t *info;
|
|
int options;
|
|
struct rusage *rusage;
|
|
{
|
|
#ifdef PIOCUSAGE
|
|
int f;
|
|
char cproc[32];
|
|
prusage_t prusage;
|
|
#endif
|
|
struct tms tms_stop;
|
|
siginfo_t info2;
|
|
|
|
if ((options & WNOHANG) && (info->si_pid == 0))
|
|
return (0); /* no children */
|
|
|
|
if (rusage == 0)
|
|
goto norusage;
|
|
|
|
wait_times(info, rusage);
|
|
#ifdef PIOCUSAGE
|
|
sprintf(cproc, "/proc/%d", info->si_pid);
|
|
if ((f = open(cproc, 0)) < 0)
|
|
goto norusage;
|
|
if (ioctl(f, PIOCUSAGE, &prusage) < 0) {
|
|
close(f);
|
|
goto norusage;
|
|
}
|
|
close(f);
|
|
#ifdef COMMENT
|
|
Missing fields:
|
|
rusage->ru_maxrss = XXX;
|
|
rusage->ru_ixrss = XXX;
|
|
rusage->ru_idrss = XXX;
|
|
rusage->ru_isrss = XXX;
|
|
#endif
|
|
rusage->ru_minflt = prusage.pr_minf;
|
|
rusage->ru_majflt = prusage.pr_majf;
|
|
rusage->ru_nswap = prusage.pr_nswap;
|
|
rusage->ru_inblock = prusage.pr_inblk;
|
|
rusage->ru_oublock = prusage.pr_oublk;
|
|
rusage->ru_msgsnd = prusage.pr_msnd;
|
|
rusage->ru_msgrcv = prusage.pr_mrcv;
|
|
rusage->ru_nsignals = prusage.pr_sigs;
|
|
rusage->ru_nvcsw = prusage.pr_vctx;
|
|
rusage->ru_nivcsw = prusage.pr_ictx;
|
|
#endif
|
|
norusage:
|
|
return (waitid(P_PID, info->si_pid, &info2, options));
|
|
}
|
|
|
|
/*
|
|
* Convert the status code to old style wait status
|
|
*/
|
|
static int wait_status(code, status)
|
|
int code;
|
|
int status;
|
|
{
|
|
register int stat = (status & 0377);
|
|
|
|
switch (code) {
|
|
|
|
case CLD_EXITED:
|
|
stat <<= 8;
|
|
break;
|
|
case CLD_KILLED:
|
|
break;
|
|
case CLD_DUMPED:
|
|
stat |= WCOREFLG;
|
|
break;
|
|
case CLD_TRAPPED:
|
|
case CLD_STOPPED:
|
|
stat <<= 8;
|
|
stat |= WSTOPFLG;
|
|
break;
|
|
case CLD_CONTINUED:
|
|
stat = WCONTFLG;
|
|
break;
|
|
}
|
|
return (stat);
|
|
}
|
|
|
|
/*
|
|
* Convert the siginfo times to rusage timeval
|
|
*/
|
|
static void wait_times(info, rusage)
|
|
siginfo_t *info;
|
|
struct rusage *rusage;
|
|
{
|
|
int hz = HZ; /* HZ is mapped into sysconf(_SC_CLK_TCK) */
|
|
|
|
rusage->ru_utime.tv_sec = info->si_utime / hz;
|
|
rusage->ru_utime.tv_usec = (info->si_utime % hz) * 1000000 / hz;
|
|
|
|
rusage->ru_stime.tv_sec = info->si_stime / hz;
|
|
rusage->ru_stime.tv_usec = (info->si_stime % hz) * 1000000 / hz;
|
|
}
|
|
|
|
#endif /* WNOWAIT */
|
|
|
|
/* @(#)resource.h 2.10 89/02/21 SMI; from UCB 4.1 83/02/10 */
|
|
/*
|
|
* Missing parts for wait3() taken from SunOS 4.1
|
|
*/
|
|
|
|
#ifndef _resource_h
|
|
#define _resource_h
|
|
|
|
/*
|
|
* Get rest of definitions from system include files
|
|
*/
|
|
#include <sys/resource.h>
|
|
|
|
/*
|
|
* Resource utilization information.
|
|
*/
|
|
|
|
#define RUSAGE_SELF 0
|
|
#define RUSAGE_CHILDREN -1
|
|
|
|
struct rusage {
|
|
struct timeval ru_utime; /* user time used */
|
|
struct timeval ru_stime; /* system time used */
|
|
long ru_maxrss;
|
|
#define ru_first ru_ixrss
|
|
long ru_ixrss; /* XXX: 0 */
|
|
long ru_idrss; /* XXX: sum of rm_asrss */
|
|
long ru_isrss; /* XXX: 0 */
|
|
long ru_minflt; /* any page faults not requiring I/O */
|
|
long ru_majflt; /* any page faults requiring I/O */
|
|
long ru_nswap; /* swaps */
|
|
long ru_inblock; /* block input operations */
|
|
long ru_oublock; /* block output operations */
|
|
long ru_msgsnd; /* messages sent */
|
|
long ru_msgrcv; /* messages received */
|
|
long ru_nsignals; /* signals received */
|
|
long ru_nvcsw; /* voluntary context switches */
|
|
long ru_nivcsw; /* involuntary " */
|
|
#define ru_last ru_nivcsw
|
|
};
|
|
|
|
#endif /* _resource_h */
|
|
|
|
|
|
------------------
|
|
strptime
|
|
-----------------
|
|
|
|
/*
|
|
* Copyright (c) 1994 Powerdog Industries. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. All advertising materials mentioning features or use of this
|
|
* software must display the following acknowledgement:
|
|
* This product includes software developed by Powerdog Industries.
|
|
* 4. The name of Powerdog Industries may not be used to endorse or
|
|
* promote products derived from this software without specific prior
|
|
* written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char copyright[] =
|
|
"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
|
|
static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
|
|
#endif /* not lint */
|
|
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#include <locale.h>
|
|
#include <string.h>
|
|
|
|
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
|
|
|
|
#ifndef sun
|
|
struct dtconv {
|
|
char *abbrev_month_names[12];
|
|
char *month_names[12];
|
|
char *abbrev_weekday_names[7];
|
|
char *weekday_names[7];
|
|
char *time_format;
|
|
char *sdate_format;
|
|
char *dtime_format;
|
|
char *am_string;
|
|
char *pm_string;
|
|
char *ldate_format;
|
|
};
|
|
#endif
|
|
|
|
static struct dtconv En_US = {
|
|
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
|
|
{ "January", "February", "March", "April",
|
|
"May", "June", "July", "August",
|
|
"September", "October", "November", "December" },
|
|
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
|
|
{ "Sunday", "Monday", "Tuesday", "Wednesday",
|
|
"Thursday", "Friday", "Saturday" },
|
|
"%H:%M:%S",
|
|
"%m/%d/%y",
|
|
"%a %b %e %T %Z %Y",
|
|
"AM",
|
|
"PM",
|
|
"%A, %B, %e, %Y"
|
|
};
|
|
|
|
#ifdef SUNOS4
|
|
extern int strncasecmp();
|
|
#endif
|
|
|
|
char *
|
|
strptime(char *buf, char *fmt, struct tm *tm)
|
|
{
|
|
char c,
|
|
*ptr;
|
|
int i,
|
|
len;
|
|
|
|
ptr = fmt;
|
|
while (*ptr != 0) {
|
|
if (*buf == 0)
|
|
break;
|
|
|
|
c = *ptr++;
|
|
|
|
if (c != '%') {
|
|
if (isspace(c))
|
|
while (*buf != 0 && isspace(*buf))
|
|
buf++;
|
|
else if (c != *buf++)
|
|
return 0;
|
|
continue;
|
|
}
|
|
|
|
c = *ptr++;
|
|
switch (c) {
|
|
case 0:
|
|
case '%':
|
|
if (*buf++ != '%')
|
|
return 0;
|
|
break;
|
|
|
|
case 'C':
|
|
buf = strptime(buf, En_US.ldate_format, tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'c':
|
|
buf = strptime(buf, "%x %X", tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'D':
|
|
buf = strptime(buf, "%m/%d/%y", tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'R':
|
|
buf = strptime(buf, "%H:%M", tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'r':
|
|
buf = strptime(buf, "%I:%M:%S %p", tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'T':
|
|
buf = strptime(buf, "%H:%M:%S", tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'X':
|
|
buf = strptime(buf, En_US.time_format, tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'x':
|
|
buf = strptime(buf, En_US.sdate_format, tm);
|
|
if (buf == 0)
|
|
return 0;
|
|
break;
|
|
|
|
case 'j':
|
|
if (!isdigit(*buf))
|
|
return 0;
|
|
|
|
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
|
i *= 10;
|
|
i += *buf - '0';
|
|
}
|
|
if (i > 365)
|
|
return 0;
|
|
|
|
tm->tm_yday = i;
|
|
break;
|
|
|
|
case 'M':
|
|
case 'S':
|
|
if (*buf == 0 || isspace(*buf))
|
|
break;
|
|
|
|
if (!isdigit(*buf))
|
|
return 0;
|
|
|
|
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
|
i *= 10;
|
|
i += *buf - '0';
|
|
}
|
|
if (i > 59)
|
|
return 0;
|
|
|
|
if (c == 'M')
|
|
tm->tm_min = i;
|
|
else
|
|
tm->tm_sec = i;
|
|
|
|
if (*buf != 0 && isspace(*buf))
|
|
while (*ptr != 0 && !isspace(*ptr))
|
|
ptr++;
|
|
break;
|
|
|
|
case 'H':
|
|
case 'I':
|
|
case 'k':
|
|
case 'l':
|
|
if (!isdigit(*buf))
|
|
return 0;
|
|
|
|
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
|
i *= 10;
|
|
i += *buf - '0';
|
|
}
|
|
if (c == 'H' || c == 'k') {
|
|
if (i > 23)
|
|
return 0;
|
|
} else if (i > 11)
|
|
return 0;
|
|
|
|
tm->tm_hour = i;
|
|
|
|
if (*buf != 0 && isspace(*buf))
|
|
while (*ptr != 0 && !isspace(*ptr))
|
|
ptr++;
|
|
break;
|
|
|
|
case 'p':
|
|
len = strlen(En_US.am_string);
|
|
if (strncasecmp(buf, En_US.am_string, len) == 0) {
|
|
if (tm->tm_hour > 12)
|
|
return 0;
|
|
if (tm->tm_hour == 12)
|
|
tm->tm_hour = 0;
|
|
buf += len;
|
|
break;
|
|
}
|
|
|
|
len = strlen(En_US.pm_string);
|
|
if (strncasecmp(buf, En_US.pm_string, len) == 0) {
|
|
if (tm->tm_hour > 12)
|
|
return 0;
|
|
if (tm->tm_hour != 12)
|
|
tm->tm_hour += 12;
|
|
buf += len;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 'A':
|
|
case 'a':
|
|
for (i = 0; i < asizeof(En_US.weekday_names); i++) {
|
|
len = strlen(En_US.weekday_names[i]);
|
|
if (strncasecmp(buf,
|
|
En_US.weekday_names[i],
|
|
len) == 0)
|
|
break;
|
|
|
|
len = strlen(En_US.abbrev_weekday_names[i]);
|
|
if (strncasecmp(buf,
|
|
En_US.abbrev_weekday_names[i],
|
|
len) == 0)
|
|
break;
|
|
}
|
|
if (i == asizeof(En_US.weekday_names))
|
|
return 0;
|
|
|
|
tm->tm_wday = i;
|
|
buf += len;
|
|
break;
|
|
|
|
case 'd':
|
|
case 'e':
|
|
if (!isdigit(*buf))
|
|
return 0;
|
|
|
|
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
|
i *= 10;
|
|
i += *buf - '0';
|
|
}
|
|
if (i > 31)
|
|
return 0;
|
|
|
|
tm->tm_mday = i;
|
|
|
|
if (*buf != 0 && isspace(*buf))
|
|
while (*ptr != 0 && !isspace(*ptr))
|
|
ptr++;
|
|
break;
|
|
|
|
case 'B':
|
|
case 'b':
|
|
case 'h':
|
|
for (i = 0; i < asizeof(En_US.month_names); i++) {
|
|
len = strlen(En_US.month_names[i]);
|
|
if (strncasecmp(buf,
|
|
En_US.month_names[i],
|
|
len) == 0)
|
|
break;
|
|
|
|
len = strlen(En_US.abbrev_month_names[i]);
|
|
if (strncasecmp(buf,
|
|
En_US.abbrev_month_names[i],
|
|
len) == 0)
|
|
break;
|
|
}
|
|
if (i == asizeof(En_US.month_names))
|
|
return 0;
|
|
|
|
tm->tm_mon = i;
|
|
buf += len;
|
|
break;
|
|
|
|
case 'm':
|
|
if (!isdigit(*buf))
|
|
return 0;
|
|
|
|
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
|
i *= 10;
|
|
i += *buf - '0';
|
|
}
|
|
if (i < 1 || i > 12)
|
|
return 0;
|
|
|
|
tm->tm_mon = i - 1;
|
|
|
|
if (*buf != 0 && isspace(*buf))
|
|
while (*ptr != 0 && !isspace(*ptr))
|
|
ptr++;
|
|
break;
|
|
|
|
case 'Y':
|
|
case 'y':
|
|
if (*buf == 0 || isspace(*buf))
|
|
break;
|
|
|
|
if (!isdigit(*buf))
|
|
return 0;
|
|
|
|
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
|
i *= 10;
|
|
i += *buf - '0';
|
|
}
|
|
if (c == 'Y')
|
|
i -= 1900;
|
|
if (i < 0)
|
|
return 0;
|
|
|
|
tm->tm_year = i;
|
|
|
|
if (*buf != 0 && isspace(*buf))
|
|
while (*ptr != 0 && !isspace(*ptr))
|
|
ptr++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
-----------------------------------------------------------
|
|
|
|
4)* TOPIC: BSD/Solaris 1/POSIX Signal Primer
|
|
|
|
[Last modified: 23 Feburary 95]
|
|
|
|
|
|
The most common problem encountered when porting BSD/Solaris 1
|
|
signal code is that Solaris 2 (and SVR4) handles interrupted
|
|
systems calls differently than does BSD. In Solaris 2 (SVR4),
|
|
system calls are interrupted and return EINTR, unless the call is
|
|
read, write, or some other call that returns the number of bytes
|
|
read/written (unless 0 bytes have been read/written, in which
|
|
case the call returns EINTR).
|
|
|
|
On the other hand, system calls are restarted on BSD/Solaris 1
|
|
systems. The signal calls can be made to restart by specifying a
|
|
SA_RESTART with sigaction(). Note, however, that code that
|
|
relies on restartable system calls is generally considered bad
|
|
practice. The following code is provided for illustrative
|
|
purposes only. It is recommended that you remove these
|
|
dependencies. Sigaction is the preferred (POSIX) way of
|
|
installing signal handlers.
|
|
|
|
|
|
|
|
The BSD/Solaris 1 code
|
|
|
|
omask = sigblock(sigmask(SIGXXX));
|
|
do_stuff_while_SIGXXX_blocked();
|
|
(void)sigsetmask(omask);
|
|
|
|
can be emulated by
|
|
|
|
sigset_t block, oblock;
|
|
struct sigaction act, oact;
|
|
....
|
|
(void)sigemptyset(&block);
|
|
(void)sigaddset(&block, SIGXXX);
|
|
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
|
|
perror("sigprocmask");
|
|
do_stuff_while_SIGXXX_blocked();
|
|
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
|
|
#ifdef SA_RESTART /* make restartable */
|
|
act.sa_flags = SA_RESTART;
|
|
#endif /* SA_RESTART */
|
|
if (sigaction(SIGXXX, &act, &oact) < 0)
|
|
return(SIG_ERR);
|
|
|
|
|
|
Note that this (emulating) construct is also available on
|
|
Solaris 1 (sans SA_RESTART), so should work on either
|
|
Solaris 1 or SVR4.
|
|
|
|
Another possibility would be to emulate BSD signal(2)
|
|
semantics as follows:
|
|
|
|
Sigfunc *bsdsignal(int signo, Sigfunc *alarm_catcher)
|
|
{
|
|
|
|
struct sigaction act;
|
|
act.sa_handler = alarm_catcher;
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_flags = SA_RESTART;
|
|
if(sigaction(signo, &act,NULL) == -1) {
|
|
perror("signal:");
|
|
return(SIG_ERR);
|
|
}
|
|
|
|
Another problem revolves around the use of setjmp and longjmp.
|
|
With 4.3+BSD the setjmp and longjmp save and restore the signal
|
|
mask. The default behavior for SVR4 is not to save and restore
|
|
the signal mask. Note that these calls are MT-Unsafe.
|
|
|
|
The POSIX.1 interface allows you to do either, by using a second
|
|
argument, savemask, for sigsetjmp. To cause the signal mask to be
|
|
saved and restored (emulating setjmp/longjmp behavior), use a
|
|
nonzero savemask. For example,
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <setjmp.h>
|
|
|
|
sigjmp_buf env;
|
|
int savemask;
|
|
|
|
....
|
|
|
|
savemask = 1;
|
|
#ifdef HAS_SIGSETJMP
|
|
sigsetjmp(env, savemask);
|
|
#endif HAS_SIGSETJMP
|
|
|
|
...
|
|
|
|
In this case, the sigsetjmp saves the current signal mask of the
|
|
process in the saved environment (sigjmp_buf). Now, if the
|
|
environment was saved by a call to sigsetjmp with a nonzero
|
|
savemask, then a subsequent siglongjmp call will restore the
|
|
saved signal mask.
|
|
|
|
Finally, be careful with signal handling code when you are doing
|
|
a vfork [Editor's Note: The following observation and example in
|
|
section 7. (i). comes courtesy of Paul Eggert
|
|
(eggert@twinsun.com). DM]. In Solaris 2, if a vfork'ed child
|
|
adjusts signal handling before exec'ing, signal handling is
|
|
munged in the parent in ways that lead to unreliable results; the
|
|
parent can dump core in some cases. This bug affects some widely
|
|
distributed programs, so when building a program that adjusts
|
|
signal handlers between `vfork' and `exec', be careful to
|
|
override its configuration to use `fork' instead (see section
|
|
7. (i) below for more detail).
|
|
|
|
To summarize, some basic rules are:
|
|
|
|
(i). Limit signal handling code to the POSIX interface
|
|
whenever possible.
|
|
|
|
(ii). Use sigaction to install signal handlers whenever
|
|
possible. Use Standard C's signal() only for
|
|
portability to non-POSIX systems.
|
|
|
|
(iii). Avoid code that relies on restartable system calls.
|
|
|
|
(iv). The main difference between SVR4 sigset() (not
|
|
POSIX) and SunOS 4.x/BSD signal() is that system
|
|
calls will return EINTR with sigset() but will be
|
|
restarted on BSD/SunOS 4.x. On SVR4 EINTR is only
|
|
returned when no bytes have been read/written.
|
|
|
|
(v). Watch your use of vfork.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
5) TOPIC: Waiting for Children to Exit
|
|
|
|
[Last modified: 26 October 93]
|
|
|
|
|
|
waitpid(2) is the preferred (POSIX) interface. Wait3 can be
|
|
replaced by waitpid (when you don't need the rusage). For
|
|
example, the BSD segment
|
|
|
|
while((id = wait(&stat)) >=0 && id != pid);
|
|
|
|
can be approximated using the POSIX waidpid(2) interface by code
|
|
of the form:
|
|
|
|
int status;
|
|
int options; /* e.g., WNOHANG */
|
|
....
|
|
options = WNOHANG;
|
|
if (waitpid((pid_t) -1, &status, options) == -1)
|
|
perror("waitpid");
|
|
}
|
|
|
|
|
|
Note here that if you execute a signal(SIGCHLD, SIG_IGN) or
|
|
sigset(SIGCHLD, SIG_IGN), Solaris will discard all child exit
|
|
statuses and reap the child processes without giving the parent a
|
|
chance to wait. That is, waitpid(2) will return -1 with an ECHILD.
|
|
|
|
|
|
Another possibility is emulate the BSD wait(2) call with SVR4's
|
|
waitid(2). The code fragment below is an example. In this case,
|
|
we wait for a particular child in our process group ((pid_t) 0)
|
|
to exit (WEXITED).
|
|
|
|
|
|
#ifdef SVR4
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
siginfo_t stat;
|
|
int retcode;
|
|
#else
|
|
union wait stat;
|
|
#endif
|
|
|
|
.....
|
|
|
|
#ifdef SVR4
|
|
while (retcode = waitid(P_ALL,(pid_t) 0, &stat, WEXITED)) {
|
|
if (retcode < 0) {
|
|
perror("waitid");
|
|
exit(1);
|
|
}
|
|
if (stat.si_pid == pid)
|
|
break;
|
|
}
|
|
#else /* BSD */
|
|
while((id = wait(&stat)) >=0 && id != pid);
|
|
#endif /* SVR4 */
|
|
|
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
6) TOPIC: Dealing With Shadow Password Files
|
|
|
|
[Last modified: 19 August 93]
|
|
|
|
The following code segment outlines how to handle shadow password
|
|
files. In the outline below, <passwd> is the clear text password.
|
|
Note that shadow passwords are part of SVR4, so again we have the
|
|
conflict between using high level system definitions (e.g., SVR4)
|
|
and feature definitions (for systems other than SVR4). I'll use
|
|
feature a feature definition (HAVE_SHADOW_H) to illustrate this.
|
|
|
|
|
|
#ifdef HAVE_SHADOW_H
|
|
#include <shadow.h>
|
|
register struct spwd *sp;
|
|
#endif /* HAVE_SHADOW_H */
|
|
|
|
.....
|
|
|
|
#ifdef HAVE_SHADOW_H
|
|
if ((sp = getspnam(<username>)) == NULL)
|
|
<no password entry for username>
|
|
if (sp->sp_pwdp == NULL)
|
|
<NULL password for username>
|
|
if (strcmp (crypt (<passwd>, sp->sp_pwdp), sp->sp_pwdp) != 0)
|
|
#else
|
|
if ((pw = getpwnam(<username>)) == NULL)
|
|
<no password entry for username>
|
|
if (pw->pw_passwd == NULL)
|
|
<NULL password for username>
|
|
if (strcmp (crypt (<passwd>, pw->pw_passwd), pw->pw_passwd) != 0)
|
|
#endif /* HAVE_SHADOW_H */
|
|
<incorrect password for username>
|
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
7) TOPIC: Some Compatibility Problems
|
|
|
|
[Last modified: 23 September 95]
|
|
|
|
|
|
|
|
(i). vfork doesn't work in Solaris 2
|
|
|
|
[Editor's Note: The following observation and
|
|
example comes courtesy of Paul Eggert
|
|
(eggert@twinsun.com). DM]
|
|
|
|
In Solaris 2, if a vfork'ed child adjusts signal
|
|
handling before exec'ing, signal handling is munged in
|
|
the parent in ways that lead to unreliable results;
|
|
the parent can dump core in some cases. This bug
|
|
affects some widely distributed programs, so when
|
|
building a program that adjusts signal handlers
|
|
between `vfork' and `exec', be careful to override its
|
|
configuration to use `fork' instead.
|
|
|
|
Sun doesn't consider this behavior to be a bug,
|
|
so it's not likely to be fixed.
|
|
|
|
Here's an illustration of the bug. This program
|
|
works fine in SunOS 4.1.x, but dumps core in
|
|
Solaris 2.x.
|
|
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef SIGLOST /* must be SunOS 4.1.x */
|
|
#include <vfork.h>
|
|
#endif
|
|
|
|
int signalled;
|
|
|
|
void catch (sig)
|
|
int sig;
|
|
{
|
|
signalled = 1;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
signal (SIGINT, catch);
|
|
if (vfork () == 0) { /* child */
|
|
signal (SIGINT, SIG_IGN);
|
|
execlp ("sleep", "sleep", "10", (char *) 0);
|
|
}
|
|
|
|
/* parent here */
|
|
|
|
kill (getpid (), SIGINT);
|
|
return signalled != 1;
|
|
}
|
|
|
|
(ii). Regarding the observation surrounding Paul
|
|
Eggert's vfork comments in (i). above, Joerg
|
|
Schilling has pointed out that the vfork code in
|
|
the kernel has not changed since SunOS 4.0. The
|
|
following text is lifted directly from Joerg's
|
|
note.
|
|
|
|
If you run the sample program under control of
|
|
truss(1) you can prove that signal(3) calls
|
|
sigaction(2) which really is a library routine on
|
|
SVr4 (not only on Solaris 2.x).
|
|
|
|
This library routine does not setup the signal
|
|
handler in the kernel directly. If the signal
|
|
handler is not SIG_IGN/SIG_DFLT it sets up a user
|
|
level dispathing function which calls the signal
|
|
handler through a table. If you use vfork(), this
|
|
table is shared between both processes. -- The
|
|
kernel code correctly changes the signal handler
|
|
only in the child. But as vfork() shares all data
|
|
between child and parent the dispatching table in
|
|
the parent process gets trashed by the child and
|
|
the parent dies on a memory address alignment
|
|
error -- the value of SIG_IGN is 1.
|
|
|
|
If you consider this to be a bug you should call
|
|
Sun and request a fix for libc.
|
|
|
|
To avoid this problem each process that calls
|
|
vfork should not use any routine that modifies
|
|
global data: signal(), sigaction(), exit() and
|
|
malloc() are possible sources of trouble.
|
|
|
|
The man page for vfork() correctly lists only
|
|
exit() as a source of problems -- it should be
|
|
updated to list all possible problems.
|
|
|
|
Users of vfork() should be very carefully and:
|
|
|
|
- Use _exit() instead of exit()
|
|
- Use __sigaction() instead of sigaction()
|
|
- Save child allocated storage in global pointers
|
|
and free them in the parent process after
|
|
returning from vfork().
|
|
|
|
To prove my statements I include a modified
|
|
version of the sample code from Paul Eggert
|
|
(eggert@twinsun.com) that is able to use the
|
|
syscall version of signal() and sigaction(). If
|
|
the syscalls are used directly, the code runs as
|
|
in SunOS 4.x, if the library routine signal(3) is
|
|
used, the code dumps core as explained above:
|
|
|
|
/*
|
|
* vfork.c
|
|
*
|
|
* compile: cc -o vfork vfork.c
|
|
*
|
|
* test:
|
|
* ./vfork - will dump core
|
|
* ./vfork syscall - calls syscall version of signal() -- OK
|
|
* ./vfork sigaction - calls syscall version of sigaction() -- OK
|
|
*/
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <sys/syscall.h>
|
|
|
|
#ifdef SIGLOST /* must be SunOS 4.1.x */
|
|
#include <vfork.h>
|
|
#endif
|
|
|
|
int signalled;
|
|
|
|
void catch (sig)
|
|
int sig;
|
|
{
|
|
signalled = 1;
|
|
}
|
|
|
|
int main(ac, av)
|
|
int ac;
|
|
char *av[];
|
|
{
|
|
int how = 0;
|
|
|
|
if (ac > 1) {
|
|
if (strcmp(av[1], "syscall") == 0)
|
|
how = 1;
|
|
else if (strcmp(av[1], "sigaction") == 0)
|
|
how = 2;
|
|
}
|
|
|
|
signal (SIGINT, catch);
|
|
|
|
if (vfork () == 0) { /* child */
|
|
|
|
#ifdef SYS_signal /* it's SVR4 */
|
|
if (how == 1) {
|
|
syscall(SYS_signal, SIGINT, SIG_IGN);
|
|
} else if (how == 2) {
|
|
struct sigaction act;
|
|
|
|
act.sa_handler = SIG_IGN;
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_flags = SA_RESTART;
|
|
|
|
__sigaction(SIGINT, &act, 0); /* real syscall */
|
|
} else {
|
|
signal (SIGINT, SIG_IGN);
|
|
}
|
|
#else
|
|
signal (SIGINT, SIG_IGN);
|
|
#endif
|
|
execlp ("sleep", "sleep", "10", (char *) 0);
|
|
}
|
|
|
|
/* parent here */
|
|
|
|
kill (getpid (), SIGINT);
|
|
return signalled != 1;
|
|
}
|
|
|
|
(iii). So, then, what is the story with vfork?
|
|
|
|
The problem with vfork() and signals has been
|
|
understoond for some time. In addition, good
|
|
practice requires that programs do some signal
|
|
housekeeping when using vfork(). This is the case
|
|
on even on SunOS 4.x.
|
|
|
|
Now, it is possible to write a correct program
|
|
using vfork() and signals only using documented
|
|
interfaces. This is demonstrated below in code
|
|
contributed by J"org Schilling.
|
|
|
|
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef SIGLOST /* must be SunOS 4.1.x */
|
|
#include <vfork.h>
|
|
#endif
|
|
|
|
#ifdef SIGHOLD /* must be SVR4 */
|
|
#define signal sigset /* use reliable signals on SVR4 */
|
|
#endif
|
|
|
|
int signalled;
|
|
|
|
void catch (sig)
|
|
int sig;
|
|
{
|
|
/*
|
|
* first reestablish handler:
|
|
* needed on SVR4 no op on BSD
|
|
*/
|
|
signal (SIGINT, catch);
|
|
signalled = 1;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
int pid;
|
|
int oldmask;
|
|
|
|
signal (SIGINT, catch);
|
|
|
|
/* do something ... */
|
|
|
|
/*
|
|
* prepare for doing vfork()
|
|
* block signals managed during vfork()
|
|
*/
|
|
#ifdef SIGHOLD
|
|
sighold(SIGINT); /* SVR4 version */
|
|
#else
|
|
oldmask = sigblock(sigmask(SIGINT)); /* BSD version */
|
|
#endif
|
|
pid = vfork();
|
|
if (pid < 0) {
|
|
perror("fork");
|
|
exit(-1);
|
|
}
|
|
if (pid == 0) { /* child */
|
|
signal (SIGINT, SIG_IGN);
|
|
/*
|
|
* enable child signals
|
|
*/
|
|
#ifdef SIGHOLD
|
|
sigrelse(SIGINT); /* SVR4 version */
|
|
#else
|
|
sigsetmask(oldmask); /* BSD version */
|
|
#endif
|
|
execlp ("sleep", "sleep", "10", (char *) 0);
|
|
} else {
|
|
/*
|
|
* Re-establish old signals in parent ...
|
|
* IMPORTANT: first restore signal handler
|
|
* then unblock held signals
|
|
*/
|
|
signal (SIGINT, catch);
|
|
#ifdef SIGHOLD
|
|
sigrelse(SIGINT); /* SVR4 version */
|
|
#else
|
|
sigsetmask(oldmask); /* BSD version */
|
|
#endif
|
|
}
|
|
|
|
/* parent here */
|
|
|
|
kill (getpid (), SIGINT);
|
|
return signalled != 1;
|
|
}
|
|
|
|
|
|
Lesson: Use vfork with care.
|
|
|
|
|
|
(iv). chown(2) does not allow uid/gid values greater
|
|
than 60002 on Solaris 2.[0-3]. Check /usr/include/limits.h,
|
|
which contains:
|
|
|
|
#define UID_MAX 60002
|
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
8) TOPIC: Other Resources
|
|
|
|
[Last modified: 27 September 93]
|
|
|
|
Porting to Solaris 2
|
|
--------------------
|
|
|
|
A excellent text on this subject is "Solaris Porting Guide",
|
|
SunSoft ISV Engineering, et. al., Prentice Hall, 1993. ISBN
|
|
0-13-030396-8.
|
|
|
|
Solaris 2 General FAQ
|
|
---------------------
|
|
|
|
The official Solaris 2 Frequently Answered Questions is
|
|
maintained by Ian Darwin, ian@sq.com, and is posted once or twice
|
|
a month to various newsgroups including comp.unix.solaris and
|
|
comp.answers.
|
|
|
|
General
|
|
-------
|
|
|
|
"Internetworking with TCP/IP: Volume III Client-Server Programming
|
|
& Applications (AT&T TLI Edition)", Douglas E. Comer & David L.
|
|
Stevens, Prentice-Hall. ISBN 0-13-474230-3. Nice reference for
|
|
TLI programming, etc.
|
|
|
|
"Networking Applications on UNIX System V", Mike Padovano, ISBN
|
|
013-613555. A good reference for System V.
|
|
|
|
"UNIX, POSIX, and Open Systems: The Open Standards Puzzle", John
|
|
S. Quarterman and Susanne Wilhelm, Addison-Wesley, 1993. ISBN
|
|
0-201-52772-3. Another nice modern reference.
|
|
|
|
"UNIX System V Network Programming", Steve Rago, ISBN
|
|
0-201-56318-5. Another good System V reference.
|
|
|
|
"Advanced Programming in the UNIX Environment", W. Richard
|
|
Stevens, Addison Wesley, 1992, ISBN 0-201-56317-1, is a nice, in
|
|
depth text covering large parts of this topic.
|
|
|
|
ANSI C
|
|
------
|
|
|
|
A very nice text here is "The Standard C Library", P.J. Plauger,
|
|
Prentice Hall, 1992, ISBN 0-13-131509-9.
|
|
|
|
Another example of the many texts here is "C, a Reference
|
|
Manual", Harbison and Steele, Prentice Hall. ISBN 0-13-110933-2.
|
|
|
|
POSIX
|
|
-----
|
|
|
|
A nice reference text on the POSIX interface is "POSIX
|
|
Programmer's Guide", Donald Levine, O'Reily & Associates, 1991.
|
|
ISBN 0-937175-73-0.
|
|
|
|
|
|
ACKNOWLEDGMENTS
|
|
|
|
I would like to thank everyone who contributed to this, and I
|
|
hope that it clarifies some of these issues. I would especially
|
|
acknowledge the contributions of Casper H.S. Dik and J.G. Vons in
|
|
helping me organize my thoughts on all this.
|
|
|
|
Thanks to:
|
|
|
|
Jamshid Afshar <jamshid@ses.com>
|
|
Pedro Acebes Bayon <pacebes@tid.es>
|
|
Ian Darwin <ian@sq.com>
|
|
Casper H.S. Dik <casper@fwi.uva.nl>
|
|
Paul Eggert <eggert@twinsun.com>
|
|
Stephen L Favor <xcpslf@atom.oryx.com>
|
|
Charles Francois <cbf@gotham.east.sun.com>
|
|
Pete Hartman <pwh@bradley.bradley.edu>
|
|
Guy Harris <guy@auspex.com>
|
|
Jens-Uwe Mager <jum@anubis.han.de>
|
|
Thomas Maslen <maslen@eng.sun.com>
|
|
Richard M. Mathews <richard@astro.west.sun.com>
|
|
Davin Milun <milun@cs.buffalo.edu>
|
|
Paul Pomes <Paul-Pomes@uiuc.edu>
|
|
Andrew Roach <andrewr@ultrix.sun.com>
|
|
Kevin Ruddy <smiles@powerdog.com>
|
|
Joerg Schilling <joerg@schily.isdn.cs.tu-berlin.de>
|
|
M C Srivas <M._C._Srivas@transarc.com>
|
|
Dan Stromberg <strombrg@hydra.acs.uci.edu>
|
|
Larry W. Virden <lwv26@cas.org>
|
|
J.G. Vons <vons%ulysse@crbca1.sinet.slb.com>
|
|
Peter Wemm <peter@DIALix.oz.au>
|
|
christos@deshaw.com
|
|
jorgens@pvv.unit.no
|
|
Malte <malte@techfak.uni-bielefeld.de>
|
|
|
|
----- End of Solaris 2 Porting FAQ -- Maintained by David Meyer meyer@ns.uoregon.edu --
|
|
|
|
|
|
|
|
David M. Meyer 503/346-1747
|
|
meyer@ns.uoregon.edu
|
|
Tue May 02 04:54:54 1995
|
|
|
|
$Header: /net/network-services/disk1/home/meyer/Projects/FAQ/RCS/porting-FAQ,v 1.6 1995/05/02 11:55:21 meyer Exp $
|
|
|
|
|
|
|