home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-25 | 59.7 KB | 1,691 lines |
- Subject: Solaris 2 Porting FAQ
- Newsgroups: comp.unix.solaris,comp.answers,news.answers
- From: meyer@frostbite-falls.uoregon.edu (David M. Meyer 503/346-1747)
- Date: 13 Oct 1994 12:46:01 GMT
-
-
- Archive-name: Solaris2/porting-FAQ
- Last-modified: Thursday, October 13, 1994
- Version: 2.16
-
- Solaris 2 Porting FAQ
- [Last modified: 13 October 1994]
-
- 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: 13 September 1994]
-
- [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
-
- usleep nanosleep POSIX See nanosleep(3R) on
- Solaris 2.3 (see libposix4.a)
- For a Solaris 2.[0-2], see the
- example below.
-
-
-
-
- ------------------------------------------------------------------
-
- 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);
- }
-
-
- ------------------
- 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: 24 May 94]
-
-
- 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: 02 September 93]
-
- (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). 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>
- 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@cambium.uoregon.edu
- Fri Jul 16 14:59:28 1993
-
- $Header: /net/network-services/disk1/home/meyer/FAQ/RCS/porting-FAQ,v 1.60 1994/09/13 14:00:21 meyer Exp meyer $
-
-
-
-