home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / munetd < prev    next >
Encoding:
Text File  |  1992-05-08  |  48.4 KB  |  1,845 lines

  1. Newsgroups: comp.sources.unix
  2. From: pk@cs.few.eur.nl (Paul Kranenburg)
  3. Subject: v26i019: munetd - a more universal network superserver
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: pk@cs.few.eur.nl (Paul Kranenburg)
  8. Posting-Number: Volume 26, Issue 19
  9. Archive-Name: munetd
  10.  
  11. A modified version of the BSD inetd(8) (v 5.25) superserver,
  12. supporting RPC, UNIX domain sockets and PTY connections.
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 1 (of 1)."
  21. # Contents:  MANIFEST Makefile README daemon.c getenv.c munetd.8
  22. #   munetd.c setenv.c
  23. # Wrapped by pk@kaa on Fri Jan 17 15:15:15 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  27. else
  28. echo shar: Extracting \"'MANIFEST'\" \(362 characters\)
  29. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  30. X   File Name        Archive #    Description
  31. X-----------------------------------------------------------
  32. X MANIFEST                   1    This shipping list
  33. X Makefile                   1    
  34. X README                     1    
  35. X daemon.c                   1    
  36. X getenv.c                   1    
  37. X munetd.8                   1    
  38. X munetd.c                   1    
  39. X setenv.c                   1    
  40. END_OF_FILE
  41. if test 362 -ne `wc -c <'MANIFEST'`; then
  42.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  43. fi
  44. # end of 'MANIFEST'
  45. fi
  46. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  47.   echo shar: Will not clobber existing file \"'Makefile'\"
  48. else
  49. echo shar: Extracting \"'Makefile'\" \(1036 characters\)
  50. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  51. X#
  52. X# @(#)Makefile    1.7 92/01/17
  53. X#
  54. X
  55. X#
  56. X# Choose path names suitable for your system.
  57. X# Set RPC=0 in DEFINES below if you don't have the routines 
  58. X# `pmap_set' and `pmap_unset' in your libraries.
  59. X#
  60. X
  61. XBINDIR    =    /usr/local/etc
  62. XMANDIR    =    /usr/local/man
  63. XDEFINES    =    -DRPC=1 -D_PATH_INETDCONF=\"/etc/munetd.conf\" \
  64. X            -D_PATH_INETDPID=\"/etc/munetd.pid\"
  65. XCC    =    cc
  66. XCFLAGS    =    -O $(DEFINES)
  67. XOBJS    =    munetd.o
  68. XLIBOBJS    =    daemon.o getenv.o setenv.o
  69. XLIBS    =    -lbsd44
  70. X
  71. Xwithlib    := LIBSEARCH = -L.
  72. Xwithlib    := LIBDEP = libbsd44.a
  73. X
  74. Xall: munetd
  75. Xwithlib: $$(LIBDEP) all
  76. X
  77. Xmunetd: $(OBJS) $$(LIBDEP)
  78. X    $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBSEARCH) $(LIBS)
  79. X
  80. Xlibbsd44.a: $(LIBOBJS)
  81. X    ar crlu $@ $(LIBOBJS)
  82. X    ranlib $@
  83. X
  84. Xinstall: munetd
  85. X    install -o root -m 555 munetd $(BINDIR)
  86. X
  87. Xinstall.man: munetd.8
  88. X    install -o root -m 444 munetd.8 $(MANDIR)/man8
  89. X
  90. Xclean:
  91. X    rm -f core a.out munetd libbsd44.a *.o
  92. X
  93. Xkit:
  94. X    makekit -m README Makefile munetd.8 munetd.c getenv.c setenv.c daemon.c
  95. X
  96. Xtar:
  97. X    tar cf - README Makefile munetd.8 munetd.c getenv.c setenv.c daemon.c | \
  98. X    compress > munetd.tar.Z
  99. END_OF_FILE
  100. if test 1036 -ne `wc -c <'Makefile'`; then
  101.     echo shar: \"'Makefile'\" unpacked with wrong size!
  102. fi
  103. # end of 'Makefile'
  104. fi
  105. if test -f 'README' -a "${1}" != "-c" ; then 
  106.   echo shar: Will not clobber existing file \"'README'\"
  107. else
  108. echo shar: Extracting \"'README'\" \(1954 characters\)
  109. sed "s/^X//" >'README' <<'END_OF_FILE'
  110. X#
  111. X# @(#)README    1.1 92/01/17    - A More Universal Network superserver
  112. X#
  113. X
  114. Xmunetd(8) is a modified version of the BSD inetd(8) version 5.25, as distributed
  115. Xby several FTP archive sites. 
  116. X
  117. XFEATURES:
  118. X
  119. X    1) Listening for connections on pseudo-terminals (pty's), useful
  120. X       for programmes that expect a terminal as their stdio but you
  121. X       want to run on a network connection (eg. tip(1), lpd(8), uucp).
  122. X       Example: the configuration entry
  123. X
  124. X       /dev/ptyrf stream  pty  wait  root  /usr/local/etc/tt.jetd  tt.jetd -h pc-lw
  125. X
  126. X       would allow lpd(8) or tip(1) to connect to a Laser printer on the
  127. X       network (`tt.jetd' typically sets up the connection using TCP and
  128. X       then acts as a bi-directional transfer agent).
  129. X
  130. X    2) Support for AF_UNIX sockets on the local machine.
  131. X       As yet, I have found no useful purpose for this, but it was
  132. X       relatively easy to add. A configuration line would go like this:
  133. X
  134. X       /tmp/your-sock stream unix nowait root /etc/your-daemon <args>
  135. X
  136. X
  137. X    3) Support for RPC based daemons.
  138. X       Syntax as used by Sun Microsystems, example:
  139. X
  140. X       rusersd/1-2    dgram    rpc/udp    wait nobody /usr/etc/rpc.rusersd rpc.rusersd
  141. X
  142. X    4) Saving the process ID in a file (typically `/etc/munetd.pid') for
  143. X       easier installation of configuration changes. This comes in
  144. X       handy if you automate (as we do) the distribution of configuration
  145. X       files on a bundle of machines.
  146. X
  147. X    5) Some bug fixes (especially in the handling of HANGUP signals)
  148. X
  149. X
  150. XINSTALLATION
  151. X
  152. X    Define RPC=0 in the makefile if your libraries do not contain
  153. X    the routines `pmap_set' and `pmap_unset'.
  154. X
  155. X    Type `make withlib' if library routines `daemon' or `setenv' 
  156. X    are not available on your system.
  157. X
  158. X
  159. XTODO
  160. X    Do a better job of unregistering RPC services on SIGTERM.
  161. X    Should hold a lock on `/etc/munetd.pid' while running to
  162. X    avoid inadvertent killings.
  163. X
  164. X
  165. XFTP
  166. X
  167. X    `munetd' is available by Anonymous FTP from `kaa.cs.few.eur.nl'
  168. X    (file: `pub/munetd.tar.Z')
  169. X
  170. X
  171. XREMARKS TO
  172. X
  173. X    Paul Kranenburg (pk@cs.few.eur.nl)
  174. END_OF_FILE
  175. if test 1954 -ne `wc -c <'README'`; then
  176.     echo shar: \"'README'\" unpacked with wrong size!
  177. fi
  178. # end of 'README'
  179. fi
  180. if test -f 'daemon.c' -a "${1}" != "-c" ; then 
  181.   echo shar: Will not clobber existing file \"'daemon.c'\"
  182. else
  183. echo shar: Extracting \"'daemon.c'\" \(1580 characters\)
  184. sed "s/^X//" >'daemon.c' <<'END_OF_FILE'
  185. X/*-
  186. X * Copyright (c) 1990 The Regents of the University of California.
  187. X * All rights reserved.
  188. X *
  189. X * Redistribution and use in source and binary forms are permitted provided
  190. X * that: (1) source distributions retain this entire copyright notice and
  191. X * comment, and (2) distributions including binaries display the following
  192. X * acknowledgement:  ``This product includes software developed by the
  193. X * University of California, Berkeley and its contributors'' in the
  194. X * documentation or other materials provided with the distribution and in
  195. X * all advertising materials mentioning features or use of this software.
  196. X * Neither the name of the University nor the names of its contributors may
  197. X * be used to endorse or promote products derived from this software without
  198. X * specific prior written permission.
  199. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  200. X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  201. X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  202. X */
  203. X
  204. X#if defined(LIBC_SCCS) && !defined(lint)
  205. Xstatic char sccsid[] = "@(#)daemon.c    1.2 (Berkeley) 6/29/90";
  206. X#endif /* LIBC_SCCS and not lint */
  207. X
  208. X#include <sys/file.h>
  209. X
  210. Xdaemon(nochdir, noclose)
  211. X    int nochdir, noclose;
  212. X{
  213. X    int cpid;
  214. X
  215. X    if ((cpid = fork()) == -1)
  216. X        return (-1);
  217. X    if (cpid)
  218. X        exit(0);
  219. X    (void) setsid();
  220. X    if (!nochdir)
  221. X        (void) chdir("/");
  222. X    if (!noclose) {
  223. X        int devnull = open("/dev/null", O_RDWR, 0);
  224. X
  225. X        if (devnull != -1) {
  226. X            (void) dup2(devnull, 0);
  227. X            (void) dup2(devnull, 1);
  228. X            (void) dup2(devnull, 2);
  229. X            if (devnull > 2)
  230. X                (void) close(devnull);
  231. X        }
  232. X    }
  233. X}
  234. END_OF_FILE
  235. if test 1580 -ne `wc -c <'daemon.c'`; then
  236.     echo shar: \"'daemon.c'\" unpacked with wrong size!
  237. fi
  238. # end of 'daemon.c'
  239. fi
  240. if test -f 'getenv.c' -a "${1}" != "-c" ; then 
  241.   echo shar: Will not clobber existing file \"'getenv.c'\"
  242. else
  243. echo shar: Extracting \"'getenv.c'\" \(2044 characters\)
  244. sed "s/^X//" >'getenv.c' <<'END_OF_FILE'
  245. X/*
  246. X * Copyright (c) 1987 Regents of the University of California.
  247. X * All rights reserved.
  248. X *
  249. X * Redistribution and use in source and binary forms are permitted
  250. X * provided that: (1) source distributions retain this entire copyright
  251. X * notice and comment, and (2) distributions including binaries display
  252. X * the following acknowledgement:  ``This product includes software
  253. X * developed by the University of California, Berkeley and its contributors''
  254. X * in the documentation or other materials provided with the distribution
  255. X * and in all advertising materials mentioning features or use of this
  256. X * software. Neither the name of the University nor the names of its
  257. X * contributors may be used to endorse or promote products derived
  258. X * from this software without specific prior written permission.
  259. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  260. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  261. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  262. X */
  263. X
  264. X#if defined(LIBC_SCCS) && !defined(lint)
  265. Xstatic char sccsid[] = "@(#)getenv.c    5.7 (Berkeley) 6/1/90";
  266. X#endif /* LIBC_SCCS and not lint */
  267. X
  268. X#include <stdlib.h>
  269. X#include <stddef.h>
  270. X
  271. X/*
  272. X * getenv --
  273. X *    Returns ptr to value associated with name, if any, else NULL.
  274. X */
  275. Xchar *
  276. Xgetenv(name)
  277. X    char *name;
  278. X{
  279. X    int offset;
  280. X    char *_findenv();
  281. X
  282. X    return(_findenv(name, &offset));
  283. X}
  284. X
  285. X/*
  286. X * _findenv --
  287. X *    Returns pointer to value associated with name, if any, else NULL.
  288. X *    Sets offset to be the offset of the name/value combination in the
  289. X *    environmental array, for use by setenv(3) and unsetenv(3).
  290. X *    Explicitly removes '=' in argument name.
  291. X *
  292. X *    This routine *should* be a static; don't use it.
  293. X */
  294. Xchar *
  295. X_findenv(name, offset)
  296. X    register char *name;
  297. X    int *offset;
  298. X{
  299. X    extern char **environ;
  300. X    register int len;
  301. X    register char **P, *C;
  302. X
  303. X    for (C = name, len = 0; *C && *C != '='; ++C, ++len);
  304. X    for (P = environ; *P; ++P)
  305. X        if (!strncmp(*P, name, len))
  306. X            if (*(C = *P + len) == '=') {
  307. X                *offset = P - environ;
  308. X                return(++C);
  309. X            }
  310. X    return(NULL);
  311. X}
  312. END_OF_FILE
  313. if test 2044 -ne `wc -c <'getenv.c'`; then
  314.     echo shar: \"'getenv.c'\" unpacked with wrong size!
  315. fi
  316. # end of 'getenv.c'
  317. fi
  318. if test -f 'munetd.8' -a "${1}" != "-c" ; then 
  319.   echo shar: Will not clobber existing file \"'munetd.8'\"
  320. else
  321. echo shar: Extracting \"'munetd.8'\" \(5717 characters\)
  322. sed "s/^X//" >'munetd.8' <<'END_OF_FILE'
  323. X.\" Copyright (c) 1985 The Regents of the University of California.
  324. X.\" All rights reserved.
  325. X.\"
  326. X.\" Redistribution and use in source and binary forms are permitted provided
  327. X.\" that: (1) source distributions retain this entire copyright notice and
  328. X.\" comment, and (2) distributions including binaries display the following
  329. X.\" acknowledgement:  ``This product includes software developed by the
  330. X.\" University of California, Berkeley and its contributors'' in the
  331. X.\" documentation or other materials provided with the distribution and in
  332. X.\" all advertising materials mentioning features or use of this software.
  333. X.\" Neither the name of the University nor the names of its contributors may
  334. X.\" be used to endorse or promote products derived from this software without
  335. X.\" specific prior written permission.
  336. X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  337. X.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  338. X.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  339. X.\"
  340. X.\"    @(#)inetd.8    6.6 (Berkeley) 6/24/90
  341. X.\"
  342. X.TH MUNETD 8 "January 16, 1992"
  343. X.UC 6
  344. X.SH NAME
  345. Xmunetd \- network ``super\-server''
  346. X.SH SYNOPSIS
  347. X.B munetd
  348. X[
  349. X.B \-d
  350. X] [ configuration file ]
  351. X.SH DESCRIPTION
  352. X.I Munetd
  353. Xshould be run at boot time by
  354. X.IR /etc/rc.local .
  355. XIt then listens for connections on certain
  356. Xinternet sockets.  When a connection is found on one
  357. Xof its sockets, it decides what service the socket
  358. Xcorresponds to, and invokes a program to service the request.
  359. XAfter the program is
  360. Xfinished, it continues to listen on the socket (except in some cases which
  361. Xwill be described below).  Essentially,
  362. X.I munetd
  363. Xallows running one daemon to invoke several others,
  364. Xreducing load on the system.
  365. X.PP
  366. XUpon execution,
  367. X.I munetd
  368. Xreads its configuration information from a configuration
  369. Xfile which, by default, is
  370. X.IR /etc/munetd.conf .
  371. XThere must be an entry for each field of the configuration
  372. Xfile, with entries for each field separated by a tab or
  373. Xa space.  Comments are denoted by a ``#'' at the beginning
  374. Xof a line.  There must be an entry for each field.  The
  375. Xfields of the configuration file are as follows:
  376. X.br
  377. X    service name
  378. X.br
  379. X    socket type
  380. X.br
  381. X    protocol
  382. X.br
  383. X    wait/nowait
  384. X.br
  385. X    user
  386. X.br
  387. X    server program
  388. X.br
  389. X    server program arguments
  390. X.PP
  391. XThe
  392. X.I service name
  393. Xentry is interpreted according to the
  394. X.I protocol
  395. Xfield. It can be numeric or the name of a valid service in the file
  396. X.IR /etc/services,
  397. X.IR /etc/rpc,
  398. Xa AF_UNIX pipe or a pseudo terminal, respectively for standard INET services,
  399. XRPC services, UNIX services and PTY services.
  400. XFor RPC services, the service name field consists of a name or protocol number
  401. Xfollowed by a slash and a version number or range of version numbers
  402. X(eg. rusers/1-2).
  403. XFor ``internal'' services (discussed below), the service
  404. Xname
  405. X.I must
  406. Xbe the official name of the service (that is, the first entry in
  407. X.IR /etc/services ).
  408. X.PP
  409. XThe
  410. X.I socket type
  411. Xshould be one of ``stream'', ``dgram'', ``raw'', ``rdm'', or ``seqpacket'',
  412. Xdepending on whether the socket is a stream, datagram, raw,
  413. Xreliably delivered message, or sequenced packet socket.
  414. X.PP
  415. XThe
  416. X.I protocol
  417. Xmust be ``unix'', ``pty'' or a valid protocol as given in
  418. X.IR /etc/protocols .
  419. XExamples might be ``tcp'' or ``udp''.
  420. XFor RPC services, the protocol field has the format rpc/\c
  421. X.I proto
  422. Xwhere
  423. X.I proto
  424. Xis the name of the underlying transport service (``tcp'' or ``udp'').
  425. X.PP
  426. XThe
  427. X.I wait/nowait
  428. Xentry is applicable to datagram sockets only (other sockets should
  429. Xhave a ``nowait'' entry in this space).  If a datagram server connects
  430. Xto its peer, freeing the socket so
  431. X.I munetd
  432. Xcan received further messages on the socket, it is said to be
  433. Xa ``multi-threaded'' server, and should use the ``nowait''
  434. Xentry.  For datagram servers which process all incoming datagrams
  435. Xon a socket and eventually time out, the server is said to be
  436. X``single-threaded'' and should use a ``wait'' entry.  ``Comsat'' (``biff'')
  437. Xand ``talk'' are both examples of the latter type of
  438. Xdatagram server.
  439. X.I Tftpd
  440. Xis an exception; it is a datagram server that establishes pseudo-connections.
  441. XIt must be listed as ``wait'' in order to avoid a race;
  442. Xthe server reads the first packet, creates a new socket,
  443. Xand then forks and exits to allow
  444. X.I munetd
  445. Xto check for new service requests to spawn new servers.
  446. XFor PTY services ``wait'' is the only acceptable choice,
  447. Xgiven the nature of this device.
  448. X.PP
  449. XThe
  450. X.I user
  451. Xentry should contain the user name of the user as whom the server
  452. Xshould run.  This allows for servers to be given less permission
  453. Xthan root.
  454. XThe
  455. X.I server program
  456. Xentry should contain the pathname of the program which is to be
  457. Xexecuted by
  458. X.I munetd
  459. Xwhen a request is found on its socket.  If
  460. X.I munetd
  461. Xprovides this service internally, this entry should
  462. Xbe ``internal''.
  463. X.PP
  464. XThe arguments to the server program should be just as they
  465. Xnormally are, starting with argv[0], which is the name of
  466. Xthe program.  If the service is provided internally, the
  467. Xword ``internal'' should take the place of this entry.
  468. X.PP
  469. X.I Munetd
  470. Xprovides several ``trivial'' services internally by use of
  471. Xroutines within itself.  These services are ``echo'',
  472. X``discard'', ``chargen'' (character generator), ``daytime''
  473. X(human readable time), and ``time'' (machine readable time,
  474. Xin the form of the number of seconds since midnight, January
  475. X1, 1900).  All of these services are tcp based.  For
  476. Xdetails of these services, consult the appropriate RFC
  477. Xfrom the Network Information Center.
  478. X.PP
  479. X.I Munetd
  480. Xrereads its configuration file when it receives a hangup signal, SIGHUP.
  481. XServices may be added, deleted or modified when the configuration file
  482. Xis reread.
  483. X.SH "SEE ALSO"
  484. Xcomsat(8), fingerd(8), ftpd(8), rexecd(8), rlogind(8), rshd(8),
  485. Xtelnetd(8), tftpd(8)
  486. END_OF_FILE
  487. if test 5717 -ne `wc -c <'munetd.8'`; then
  488.     echo shar: \"'munetd.8'\" unpacked with wrong size!
  489. fi
  490. # end of 'munetd.8'
  491. fi
  492. if test -f 'munetd.c' -a "${1}" != "-c" ; then 
  493.   echo shar: Will not clobber existing file \"'munetd.c'\"
  494. else
  495. echo shar: Extracting \"'munetd.c'\" \(28032 characters\)
  496. sed "s/^X//" >'munetd.c' <<'END_OF_FILE'
  497. X/*
  498. X * @(#)munetd.c    1.10 92/01/17    - pseudo tty server a la inetd
  499. X *          based on BSD 4.4 inetd.c
  500. X */
  501. X/*
  502. X * Copyright (c) 1983 Regents of the University of California.
  503. X * All rights reserved.
  504. X *
  505. X * Redistribution and use in source and binary forms are permitted provided
  506. X * that: (1) source distributions retain this entire copyright notice and
  507. X * comment, and (2) distributions including binaries display the following
  508. X * acknowledgement:  ``This product includes software developed by the
  509. X * University of California, Berkeley and its contributors'' in the
  510. X * documentation or other materials provided with the distribution and in
  511. X * all advertising materials mentioning features or use of this software.
  512. X * Neither the name of the University nor the names of its contributors may
  513. X * be used to endorse or promote products derived from this software without
  514. X * specific prior written permission.
  515. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  516. X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  517. X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  518. X */
  519. X
  520. X#ifndef lint
  521. Xchar copyright[] =
  522. X"@(#) Copyright (c) 1983 Regents of the University of California.\n\
  523. X All rights reserved.\n";
  524. X#endif /* not lint */
  525. X
  526. X#ifndef lint
  527. Xstatic char bsdsccsid[] = "@(#)inetd.c     5.25 (Berkeley) 6/29/90";
  528. Xstatic char sccsid[] = "@(#)munetd.c    1.10 (Erasmus) 1/17/92";
  529. X#endif /* not lint */
  530. X
  531. X/*
  532. X * Inetd - Internet super-server
  533. X *
  534. X * This program invokes all internet services as needed.
  535. X * connection-oriented services are invoked each time a
  536. X * connection is made, by creating a process.  This process
  537. X * is passed the connection as file descriptor 0 and is
  538. X * expected to do a getpeername to find out the source host
  539. X * and port.
  540. X *
  541. X * Datagram oriented services are invoked when a datagram
  542. X * arrives; a process is created and passed a pending message
  543. X * on file descriptor 0.  Datagram servers may either connect
  544. X * to their peer, freeing up the original socket for inetd
  545. X * to receive further messages on, or ``take over the socket'',
  546. X * processing all arriving datagrams and, eventually, timing
  547. X * out.     The first type of server is said to be ``multi-threaded'';
  548. X * the second type of server ``single-threaded''. 
  549. X *
  550. X * Inetd uses a configuration file which is read at startup
  551. X * and, possibly, at some later time in response to a hangup signal.
  552. X * The configuration file is ``free format'' with fields given in the
  553. X * order shown below.  Continuation lines for an entry must being with
  554. X * a space or tab.  All fields must be present in each entry.
  555. X *
  556. X *    service name            must be in /etc/services
  557. X *    socket type            stream/dgram/raw/rdm/seqpacket
  558. X *    protocol            must be in /etc/protocols
  559. X *    wait/nowait            single-threaded/multi-threaded
  560. X *    user                user to run daemon as
  561. X *    server program            full path name
  562. X *    server program arguments    maximum of MAXARGS (20)
  563. X *
  564. X * Comment lines are indicated by a `#' in column 1.
  565. X */
  566. X#include <sys/param.h>
  567. X#include <sys/stat.h>
  568. X#include <sys/ioctl.h>
  569. X#include <sys/socket.h>
  570. X#include <sys/un.h>
  571. X#include <sys/file.h>
  572. X#include <sys/wait.h>
  573. X#include <sys/time.h>
  574. X#include <sys/resource.h>
  575. X
  576. X#include <netinet/in.h>
  577. X#include <arpa/inet.h>
  578. X
  579. X#include <errno.h>
  580. X#include <signal.h>
  581. X#include <netdb.h>
  582. X#include <syslog.h>
  583. X#include <pwd.h>
  584. X#include <stdio.h>
  585. X#include <string.h>
  586. X#if 0
  587. X#include "pathnames.h"
  588. X#endif
  589. X
  590. X#define    TOOMANY        40        /* don't start more than TOOMANY */
  591. X#define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  592. X#define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  593. X
  594. X#define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  595. X
  596. Xextern    int errno;
  597. X
  598. Xvoid    config(), reapchild(), retry();
  599. Xchar    *index();
  600. Xchar    *malloc();
  601. X
  602. Xint    debug = 0;
  603. Xint    nsock, maxsock;
  604. Xfd_set    allsock;
  605. Xfd_set    allpty;
  606. Xint    options;
  607. Xint    timingout;
  608. Xstruct    servent *sp;
  609. X
  610. Xstruct    servtab {
  611. X    char    *se_service;        /* name of service */
  612. X    int    se_socktype;        /* type of socket to use */
  613. X    int    se_family;        /* address family */
  614. X#define AF_PTY    0xf0000000
  615. X#define isrealsock(sep)    ((sep)->se_family == AF_INET || \
  616. X            (sep)->se_family == AF_UNIX)
  617. X    char    *se_proto;        /* protocol used */
  618. X    int    se_rpcprog;        /* rpc program number */
  619. X    int    se_rpcversl;        /* rpc program lowest version */
  620. X    int    se_rpcversh;        /* rpc program highest version */
  621. X#define isrpcservice(sep)    ((sep)->se_rpcversl != 0)
  622. X    short    se_wait;        /* single threaded server */
  623. X    short    se_checked;        /* looked at during merge */
  624. X    char    *se_user;        /* user name to run as */
  625. X    struct    biltin *se_bi;        /* if built-in, description */
  626. X    char    *se_server;        /* server program */
  627. X#define    MAXARGV 20
  628. X    char    *se_argv[MAXARGV+1];    /* program arguments */
  629. X    int    se_fd;            /* open descriptor */
  630. X    union {
  631. X        struct    sockaddr se_un_ctrladdr;
  632. X        struct    sockaddr_in se_un_ctrladdr_in;
  633. X        struct    sockaddr_un se_un_ctrladdr_un;
  634. X    } se_un;            /* bound address */
  635. X#define se_ctrladdr    se_un.se_un_ctrladdr
  636. X#define se_ctrladdr_in    se_un.se_un_ctrladdr_in
  637. X#define se_ctrladdr_un    se_un.se_un_ctrladdr_un
  638. X    int    se_ctrladdr_size;
  639. X    int    se_count;        /* number started since se_time */
  640. X    struct    timeval se_time;    /* start of se_count */
  641. X    struct    servtab *se_next;
  642. X} *servtab;
  643. X
  644. Xint echo_stream(), discard_stream(), machtime_stream();
  645. Xint daytime_stream(), chargen_stream();
  646. Xint echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
  647. X
  648. Xstruct biltin {
  649. X    char    *bi_service;        /* internally provided service name */
  650. X    int    bi_socktype;        /* type of socket supported */
  651. X    short    bi_fork;        /* 1 if should fork before call */
  652. X    short    bi_wait;        /* 1 if should wait for child */
  653. X    int    (*bi_fn)();        /* function which performs it */
  654. X} biltins[] = {
  655. X    /* Echo received data */
  656. X    "echo",        SOCK_STREAM,    1, 0,    echo_stream,
  657. X    "echo",        SOCK_DGRAM,    0, 0,    echo_dg,
  658. X
  659. X    /* Internet /dev/null */
  660. X    "discard",    SOCK_STREAM,    1, 0,    discard_stream,
  661. X    "discard",    SOCK_DGRAM,    0, 0,    discard_dg,
  662. X
  663. X    /* Return 32 bit time since 1900 */
  664. X    "time",        SOCK_STREAM,    0, 0,    machtime_stream,
  665. X    "time",        SOCK_DGRAM,    0, 0,    machtime_dg,
  666. X
  667. X    /* Return human-readable time */
  668. X    "daytime",    SOCK_STREAM,    0, 0,    daytime_stream,
  669. X    "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg,
  670. X
  671. X    /* Familiar character generator */
  672. X    "chargen",    SOCK_STREAM,    1, 0,    chargen_stream,
  673. X    "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg,
  674. X    0
  675. X};
  676. X
  677. X#define NUMINT    (sizeof(intab) / sizeof(struct inent))
  678. X#ifdef _PATH_INETDCONF
  679. Xchar    *CONFIG = _PATH_INETDCONF;
  680. X#else
  681. Xchar    *CONFIG = "/etc/inetd.conf";
  682. X#endif
  683. X#ifdef _PATH_INETDPID
  684. Xchar    *PIDFILE = _PATH_INETDPID;
  685. X#else
  686. Xchar    *PIDFILE = "/etc/inetd.pid";
  687. X#endif
  688. Xchar    **Argv;
  689. Xchar     *LastArg;
  690. X
  691. Xmain(argc, argv, envp)
  692. X    int argc;
  693. X    char *argv[], *envp[];
  694. X{
  695. X    extern char *optarg;
  696. X    extern int optind;
  697. X    register struct servtab *sep;
  698. X    register struct passwd *pwd;
  699. X    register int tmpint;
  700. X    struct sigvec sv;
  701. X    int ch, pid, dofork;
  702. X    char buf[50];
  703. X
  704. X    Argv = argv;
  705. X    if (envp == 0 || *envp == 0)
  706. X        envp = argv;
  707. X    while (*envp)
  708. X        envp++;
  709. X    LastArg = envp[-1] + strlen(envp[-1]);
  710. X
  711. X    while ((ch = getopt(argc, argv, "d")) != EOF)
  712. X        switch(ch) {
  713. X        case 'd':
  714. X            debug = 1;
  715. X            options |= SO_DEBUG;
  716. X            break;
  717. X        case '?':
  718. X        default:
  719. X            fprintf(stderr, "usage: munetd [-d]");
  720. X            exit(1);
  721. X        }
  722. X    argc -= optind;
  723. X    argv += optind;
  724. X
  725. X    if (argc > 0)
  726. X        CONFIG = argv[0];
  727. X#ifdef sun
  728. X    bump_nofile();
  729. X#endif
  730. X    if (debug == 0)
  731. X        daemon(0, 0);
  732. X    openlog("munetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  733. X    logpid();
  734. X    bzero((char *)&sv, sizeof(sv));
  735. X    sv.sv_mask = SIGBLOCK;
  736. X    sv.sv_handler = retry;
  737. X    sigvec(SIGALRM, &sv, (struct sigvec *)0);
  738. X    config();
  739. X    sv.sv_handler = config;
  740. X    sigvec(SIGHUP, &sv, (struct sigvec *)0);
  741. X    sv.sv_handler = reapchild;
  742. X    sigvec(SIGCHLD, &sv, (struct sigvec *)0);
  743. X
  744. X    {
  745. X        /* space for daemons to overwrite environment for ps */
  746. X#define    DUMMYSIZE    100
  747. X        char dummy[DUMMYSIZE];
  748. X
  749. X        (void)memset(dummy, 'x', DUMMYSIZE - 1);
  750. X        dummy[DUMMYSIZE - 1] = '\0';
  751. X
  752. X        (void)setenv("inetd_dummy", dummy, 1);
  753. X    }
  754. X
  755. X    for (;;) {
  756. X        int n, ctrl;
  757. X        fd_set readable, writable;
  758. X
  759. X        if (nsock == 0) {
  760. X        (void) sigblock(SIGBLOCK);
  761. X        while (nsock == 0)
  762. X            sigpause(0L);
  763. X        (void) sigsetmask(0L);
  764. X        }
  765. X        readable = allsock;
  766. X        writable = allpty;
  767. X        if ((n = select(maxsock + 1, &readable, &writable,
  768. X        (fd_set *)0, (struct timeval *)0)) <= 0) {
  769. X            if (n < 0 && errno != EINTR)
  770. X            syslog(LOG_WARNING, "select: %m\n");
  771. X            sleep(1);
  772. X            continue;
  773. X        }
  774. X        for (sep = servtab; n && sep; sep = sep->se_next)
  775. X        if (sep->se_fd != -1 && (
  776. X            FD_ISSET(sep->se_fd, &readable) ||
  777. X            FD_ISSET(sep->se_fd, &writable)    )) {
  778. X        n--;
  779. X        if (debug)
  780. X            fprintf(stderr, "someone wants %s\n", sep->se_service);
  781. X        if (isrealsock(sep) && sep->se_socktype == SOCK_STREAM) {
  782. X            ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  783. X                (int *)0);
  784. X            if (debug)
  785. X                fprintf(stderr, "accept, ctrl %d\n", ctrl);
  786. X            if (ctrl < 0) {
  787. X                if (errno == EINTR)
  788. X                    continue;
  789. X                syslog(LOG_WARNING, "accept (for %s): %m",
  790. X                    sep->se_service);
  791. X                continue;
  792. X            }
  793. X        } else
  794. X            ctrl = sep->se_fd;
  795. X        (void) sigblock(SIGBLOCK);
  796. X        pid = 0;
  797. X        dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  798. X        if (dofork) {
  799. X            if (sep->se_count++ == 0)
  800. X                (void)gettimeofday(&sep->se_time,
  801. X                    (struct timezone *)0);
  802. X            else if (sep->se_count >= TOOMANY) {
  803. X                struct timeval now;
  804. X
  805. X                (void)gettimeofday(&now, (struct timezone *)0);
  806. X                if (now.tv_sec - sep->se_time.tv_sec >
  807. X                    CNT_INTVL) {
  808. X                    sep->se_time = now;
  809. X                    sep->se_count = 1;
  810. X                } else {
  811. X                    syslog(LOG_ERR,
  812. X            "%s/%s server failing (looping), service terminated\n",
  813. X                        sep->se_service, sep->se_proto);
  814. X                    FD_CLR(sep->se_fd, &allsock);
  815. X                    if (sep->se_family == AF_PTY)
  816. X                        FD_CLR(sep->se_fd, &allpty);
  817. X                    (void) close(sep->se_fd);
  818. X                    sep->se_fd = -1;
  819. X                    sep->se_count = 0;
  820. X                    nsock--;
  821. X                    sigsetmask(0L);
  822. X                    if (!timingout) {
  823. X                        timingout = 1;
  824. X                        alarm(RETRYTIME);
  825. X                    }
  826. X                    continue;
  827. X                }
  828. X            }
  829. X            pid = fork();
  830. X        }
  831. X        if (pid < 0) {
  832. X            if (isrealsock(sep) && sep->se_socktype == SOCK_STREAM)
  833. X                close(ctrl);
  834. X            sigsetmask(0L);
  835. X            sleep(1);
  836. X            continue;
  837. X        }
  838. X        if (pid && sep->se_wait) {
  839. X            sep->se_wait = pid;
  840. X            FD_CLR(sep->se_fd, &allsock);
  841. X            if (sep->se_family == AF_PTY)
  842. X                FD_CLR(sep->se_fd, &allpty);
  843. X            nsock--;
  844. X        }
  845. X        sigsetmask(0L);
  846. X        if (pid == 0) {
  847. X            if (debug && dofork)
  848. X                setsid();
  849. X            if (sep->se_bi)
  850. X                (*sep->se_bi->bi_fn)(ctrl, sep);
  851. X            else {
  852. X                if ((pwd = getpwnam(sep->se_user)) == NULL) {
  853. X                    syslog(LOG_ERR,
  854. X                        "getpwnam: %s: No such user",
  855. X                        sep->se_user);
  856. X                    if (isrealsock(sep) &&
  857. X                        sep->se_socktype != SOCK_STREAM)
  858. X                        recv(0, buf, sizeof (buf), 0);
  859. X                    _exit(1);
  860. X                }
  861. X                if (pwd->pw_uid) {
  862. X                    (void) setgid((gid_t)pwd->pw_gid);
  863. X                    initgroups(pwd->pw_name, pwd->pw_gid);
  864. X                    (void) setuid((uid_t)pwd->pw_uid);
  865. X                }
  866. X                if (debug)
  867. X                    fprintf(stderr, "%d execl %s\n",
  868. X                        getpid(), sep->se_server);
  869. X                dup2(ctrl, 0);
  870. X                close(ctrl);
  871. X                dup2(0, 1);
  872. X                dup2(0, 2);
  873. X                for (tmpint = getdtablesize(); --tmpint > 2; )
  874. X                    (void)close(tmpint);
  875. X                execv(sep->se_server, sep->se_argv);
  876. X                if (isrealsock(sep) &&
  877. X                    sep->se_socktype != SOCK_STREAM)
  878. X                    recv(0, buf, sizeof (buf), 0);
  879. X                syslog(LOG_ERR, "execv %s: %m", sep->se_server);
  880. X                _exit(1);
  881. X            }
  882. X        }
  883. X        if (isrealsock(sep) && sep->se_socktype == SOCK_STREAM)
  884. X            close(ctrl);
  885. X        if (sep->se_family == AF_PTY) {
  886. X            close(sep->se_fd);
  887. X            sep->se_fd = -1;
  888. X        }
  889. X        }
  890. X    }
  891. X}
  892. X
  893. Xvoid
  894. Xreapchild()
  895. X{
  896. X    union wait status;
  897. X    int pid;
  898. X    register struct servtab *sep;
  899. X
  900. X    for (;;) {
  901. X        pid = wait3(&status, WNOHANG, (struct rusage *)0);
  902. X        if (pid <= 0)
  903. X            break;
  904. X        if (debug)
  905. X            fprintf(stderr, "%d reaped\n", pid);
  906. X        for (sep = servtab; sep; sep = sep->se_next)
  907. X            if (sep->se_wait == pid) {
  908. X                if (status.w_status)
  909. X                    syslog(LOG_WARNING,
  910. X                        "%s: exit status 0x%x",
  911. X                        sep->se_server, status.w_retcode);
  912. X                sep->se_wait = 1;
  913. X                if (sep->se_family == AF_PTY) {
  914. X                    setuppty(sep);
  915. X                } else {
  916. X                    FD_SET(sep->se_fd, &allsock);
  917. X                    nsock++;
  918. X                }
  919. X                if (debug)
  920. X                    fprintf(stderr, "restored %s, fd %d\n",
  921. X                        sep->se_service, sep->se_fd);
  922. X            }
  923. X    }
  924. X}
  925. X
  926. Xvoid
  927. Xconfig()
  928. X{
  929. X    register struct servtab *sep, *cp, **sepp;
  930. X    struct servtab *getconfigent(), *enter();
  931. X    long omask;
  932. X    int n;
  933. X
  934. X    if (!setconfig()) {
  935. X        syslog(LOG_ERR, "%s: %m", CONFIG);
  936. X        return;
  937. X    }
  938. X    for (sep = servtab; sep; sep = sep->se_next)
  939. X        sep->se_checked = 0;
  940. X    while (cp = getconfigent()) {
  941. X        for (sep = servtab; sep; sep = sep->se_next)
  942. X            if (strcmp(sep->se_service, cp->se_service) == 0 &&
  943. X                strcmp(sep->se_proto, cp->se_proto) == 0)
  944. X                break;
  945. X        if (sep != 0) {
  946. X            int i;
  947. X
  948. X            omask = sigblock(SIGBLOCK);
  949. X            /*
  950. X             * sep->se_wait may be holding the pid of a daemon
  951. X             * that we're waiting for.  If so, don't overwrite
  952. X             * it unless the config file explicitly says don't 
  953. X             * wait.
  954. X             */
  955. X            if (cp->se_bi == 0 && 
  956. X                (sep->se_wait == 1 || cp->se_wait == 0))
  957. X                sep->se_wait = cp->se_wait;
  958. X#define SWAP(a, b) { char *c = a; a = b; b = c; }
  959. X            if (cp->se_user)
  960. X                SWAP(sep->se_user, cp->se_user);
  961. X            if (cp->se_server)
  962. X                SWAP(sep->se_server, cp->se_server);
  963. X            for (i = 0; i < MAXARGV; i++)
  964. X                SWAP(sep->se_argv[i], cp->se_argv[i]);
  965. X            if (isrpcservice(sep))
  966. X                unregister_rpc(sep);
  967. X            sep->se_rpcversl = cp->se_rpcversl;
  968. X            sep->se_rpcversh = cp->se_rpcversh;
  969. X            sigsetmask(omask);
  970. X            freeconfig(cp);
  971. X            if (debug)
  972. X                print_service("REDO", sep);
  973. X        } else {
  974. X            sep = enter(cp);
  975. X            if (debug)
  976. X                print_service("ADD ", sep);
  977. X        }
  978. X        sep->se_checked = 1;
  979. X
  980. X        switch (sep->se_family) {
  981. X        case AF_UNIX:
  982. X            if (sep->se_fd != -1)
  983. X                break;
  984. X            (void)unlink(sep->se_service);
  985. X            n = strlen(sep->se_service);
  986. X            if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 
  987. X                n = sizeof sep->se_ctrladdr_un.sun_path - 1;
  988. X            strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
  989. X            sep->se_ctrladdr_un.sun_family = AF_UNIX;
  990. X            sep->se_ctrladdr_size = n +
  991. X                    sizeof sep->se_ctrladdr_un.sun_family;
  992. X            setup(sep);
  993. X            break;
  994. X        case AF_PTY:
  995. X            if (sep->se_fd == -1 && sep->se_wait == 1)
  996. X                setuppty(sep);
  997. X            break;
  998. X        case AF_INET:
  999. X            sep->se_ctrladdr_in.sin_family = AF_INET;
  1000. X            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
  1001. X            if (isrpcservice(sep)) {
  1002. X                struct rpcent *rp;
  1003. X
  1004. X                sep->se_rpcprog = atoi(sep->se_service);
  1005. X                if (sep->se_rpcprog == 0) {
  1006. X                    rp = getrpcbyname(sep->se_service);
  1007. X                    if (rp == 0) {
  1008. X                        syslog(LOG_ERR,
  1009. X                            "%s: unknown service",
  1010. X                            sep->se_service);
  1011. X                        continue;
  1012. X                    }
  1013. X                    sep->se_rpcprog = rp->r_number;
  1014. X                }
  1015. X                if (sep->se_fd == -1)
  1016. X                    setup(sep);
  1017. X                if (sep->se_fd != -1)
  1018. X                    register_rpc(sep);
  1019. X            } else {
  1020. X                u_short port = htons(atoi(sep->se_service));
  1021. X
  1022. X                if (!port) {
  1023. X                    sp = getservbyname(sep->se_service,
  1024. X                                sep->se_proto);
  1025. X                    if (sp == 0) {
  1026. X                        syslog(LOG_ERR,
  1027. X                            "%s/%s: unknown service",
  1028. X                            sep->se_service, sep->se_proto);
  1029. X                        continue;
  1030. X                    }
  1031. X                    port = sp->s_port;
  1032. X                }
  1033. X                if (port != sep->se_ctrladdr_in.sin_port) {
  1034. X                    sep->se_ctrladdr_in.sin_port = port;
  1035. X                    if (sep->se_fd != -1) {
  1036. X                        FD_CLR(sep->se_fd, &allsock);
  1037. X                        nsock--;
  1038. X                        (void) close(sep->se_fd);
  1039. X                    }
  1040. X                    sep->se_fd = -1;
  1041. X                }
  1042. X                if (sep->se_fd == -1)
  1043. X                    setup(sep);
  1044. X            }
  1045. X        }
  1046. X    }
  1047. X    endconfig();
  1048. X    /*
  1049. X     * Purge anything not looked at above.
  1050. X     */
  1051. X    omask = sigblock(SIGBLOCK);
  1052. X    sepp = &servtab;
  1053. X    while (sep = *sepp) {
  1054. X        if (sep->se_checked) {
  1055. X            sepp = &sep->se_next;
  1056. X            continue;
  1057. X        }
  1058. X        *sepp = sep->se_next;
  1059. X        if (sep->se_fd != -1) {
  1060. X            FD_CLR(sep->se_fd, &allsock);
  1061. X            if (sep->se_family == AF_PTY)
  1062. X                FD_CLR(sep->se_fd, &allpty);
  1063. X            nsock--;
  1064. X            (void) close(sep->se_fd);
  1065. X        }
  1066. X        if (isrpcservice(sep))
  1067. X            unregister_rpc(sep);
  1068. X        if (sep->se_family == AF_UNIX)
  1069. X            (void)unlink(sep->se_service);
  1070. X        if (debug)
  1071. X            print_service("FREE", sep);
  1072. X        freeconfig(sep);
  1073. X        free((char *)sep);
  1074. X    }
  1075. X    (void) sigsetmask(omask);
  1076. X}
  1077. X
  1078. Xvoid
  1079. Xretry()
  1080. X{
  1081. X    register struct servtab *sep;
  1082. X
  1083. X    timingout = 0;
  1084. X    for (sep = servtab; sep; sep = sep->se_next)
  1085. X        if (sep->se_fd == -1) {
  1086. X            switch (sep->se_family) {
  1087. X            case AF_UNIX:
  1088. X            case AF_INET:
  1089. X                setup(sep);
  1090. X                if (sep->se_fd != -1 && isrpcservice(sep))
  1091. X                    register_rpc(sep);
  1092. X                break;
  1093. X            case AF_PTY:
  1094. X                if (sep->se_wait == 1)
  1095. X                    setuppty(sep);
  1096. X                break;
  1097. X            }
  1098. X        }
  1099. X}
  1100. X
  1101. Xsetup(sep)
  1102. X    register struct servtab *sep;
  1103. X{
  1104. X    int on = 1;
  1105. X
  1106. X    if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
  1107. X        syslog(LOG_ERR, "%s/%s: socket: %m",
  1108. X            sep->se_service, sep->se_proto);
  1109. X        return;
  1110. X    }
  1111. X#define    turnon(fd, opt) \
  1112. Xsetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  1113. X    if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  1114. X        turnon(sep->se_fd, SO_DEBUG) < 0)
  1115. X        syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  1116. X    if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  1117. X        syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  1118. X#undef turnon
  1119. X    if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
  1120. X        syslog(LOG_ERR, "%s/%s: bind: %m",
  1121. X            sep->se_service, sep->se_proto);
  1122. X        (void) close(sep->se_fd);
  1123. X        sep->se_fd = -1;
  1124. X        if (!timingout) {
  1125. X            timingout = 1;
  1126. X            alarm(RETRYTIME);
  1127. X        }
  1128. X        return;
  1129. X    }
  1130. X    if (sep->se_socktype == SOCK_STREAM)
  1131. X        listen(sep->se_fd, 10);
  1132. X
  1133. X    FD_SET(sep->se_fd, &allsock);
  1134. X    nsock++;
  1135. X    if (sep->se_fd > maxsock)
  1136. X        maxsock = sep->se_fd;
  1137. X}
  1138. X
  1139. Xregister_rpc(sep)
  1140. X    register struct servtab *sep;
  1141. X{
  1142. X#if RPC
  1143. X    int n;
  1144. X    struct sockaddr_in sin;
  1145. X    struct protoent *pp;
  1146. X
  1147. X    if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
  1148. X        syslog(LOG_ERR, "%s: getproto: %m",
  1149. X            sep->se_proto);
  1150. X        return;
  1151. X    }
  1152. X    n = sizeof sin;
  1153. X    if (getsockname(sep->se_fd, &sin, &n) < 0) {
  1154. X        syslog(LOG_ERR, "%s/%s: getsockname: %m",
  1155. X            sep->se_service, sep->se_proto);
  1156. X        return;
  1157. X    }
  1158. X
  1159. X    for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  1160. X        if (debug)
  1161. X            fprintf(stderr, "pmap_set: %u %u %u %u\n",
  1162. X            sep->se_rpcprog, n, pp->p_proto, sin.sin_port);
  1163. X        if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, sin.sin_port))
  1164. X            syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
  1165. X            sep->se_rpcprog, n, pp->p_proto, sin.sin_port);
  1166. X    }
  1167. X#endif RPC
  1168. X}
  1169. X
  1170. Xunregister_rpc(sep)
  1171. X    register struct servtab *sep;
  1172. X{
  1173. X    int n;
  1174. X
  1175. X#if RPC
  1176. X    for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  1177. X        if (debug)
  1178. X            fprintf(stderr, "pmap_unset(%u, %u)\n",
  1179. X                sep->se_rpcprog, n);
  1180. X        if (!pmap_unset(sep->se_rpcprog, n))
  1181. X            syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
  1182. X                sep->se_rpcprog, n);
  1183. X    }
  1184. X#endif RPC
  1185. X}
  1186. X
  1187. Xsetuppty(sep)
  1188. X    register struct servtab *sep;
  1189. X{
  1190. X    if ((sep->se_fd = open(sep->se_service, O_RDWR, 0)) < 0) {
  1191. X        syslog(LOG_ERR, "%s/%s: open: %m",
  1192. X            sep->se_service, sep->se_proto);
  1193. X        if (!timingout) {
  1194. X            timingout = 1;
  1195. X            alarm(RETRYTIME);
  1196. X        }
  1197. X        return;
  1198. X    }
  1199. X    FD_SET(sep->se_fd, &allsock);
  1200. X    FD_SET(sep->se_fd, &allpty);
  1201. X    nsock++;
  1202. X    if (sep->se_fd > maxsock)
  1203. X        maxsock = sep->se_fd;
  1204. X}
  1205. X
  1206. Xstruct servtab *
  1207. Xenter(cp)
  1208. X    struct servtab *cp;
  1209. X{
  1210. X    register struct servtab *sep;
  1211. X    long omask;
  1212. X
  1213. X    sep = (struct servtab *)malloc(sizeof (*sep));
  1214. X    if (sep == (struct servtab *)0) {
  1215. X        syslog(LOG_ERR, "Out of memory.");
  1216. X        exit(-1);
  1217. X    }
  1218. X    *sep = *cp;
  1219. X    sep->se_fd = -1;
  1220. X    sep->se_rpcprog = -1;
  1221. X    omask = sigblock(SIGBLOCK);
  1222. X    sep->se_next = servtab;
  1223. X    servtab = sep;
  1224. X    sigsetmask(omask);
  1225. X    return (sep);
  1226. X}
  1227. X
  1228. XFILE    *fconfig = NULL;
  1229. Xstruct    servtab serv;
  1230. Xchar    line[256];
  1231. Xchar    *skip(), *nextline();
  1232. X
  1233. Xsetconfig()
  1234. X{
  1235. X
  1236. X    if (fconfig != NULL) {
  1237. X        fseek(fconfig, 0L, L_SET);
  1238. X        return (1);
  1239. X    }
  1240. X    fconfig = fopen(CONFIG, "r");
  1241. X    return (fconfig != NULL);
  1242. X}
  1243. X
  1244. Xendconfig()
  1245. X{
  1246. X    if (fconfig) {
  1247. X        (void) fclose(fconfig);
  1248. X        fconfig = NULL;
  1249. X    }
  1250. X}
  1251. X
  1252. Xstruct servtab *
  1253. Xgetconfigent()
  1254. X{
  1255. X    register struct servtab *sep = &serv;
  1256. X    int argc;
  1257. X    char *cp, *arg, *strdup();
  1258. X
  1259. Xmore:
  1260. X    while ((cp = nextline(fconfig)) && *cp == '#')
  1261. X        ;
  1262. X    if (cp == NULL)
  1263. X        return ((struct servtab *)0);
  1264. X    bzero((char *)sep, sizeof *sep);
  1265. X    sep->se_service = strdup(skip(&cp));
  1266. X    arg = skip(&cp);
  1267. X    if (strcmp(arg, "stream") == 0)
  1268. X        sep->se_socktype = SOCK_STREAM;
  1269. X    else if (strcmp(arg, "dgram") == 0)
  1270. X        sep->se_socktype = SOCK_DGRAM;
  1271. X    else if (strcmp(arg, "rdm") == 0)
  1272. X        sep->se_socktype = SOCK_RDM;
  1273. X    else if (strcmp(arg, "seqpacket") == 0)
  1274. X        sep->se_socktype = SOCK_SEQPACKET;
  1275. X    else if (strcmp(arg, "raw") == 0)
  1276. X        sep->se_socktype = SOCK_RAW;
  1277. X    else
  1278. X        sep->se_socktype = -1;
  1279. X
  1280. X    sep->se_proto = strdup(skip(&cp));
  1281. X    if (strcmp(sep->se_proto, "pty") == 0) {
  1282. X        sep->se_family = AF_PTY;
  1283. X    } else if (strcmp(sep->se_proto, "unix") == 0) {
  1284. X        sep->se_family = AF_UNIX;
  1285. X    } else {
  1286. X        sep->se_family = AF_INET;
  1287. X        if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
  1288. X#if RPC
  1289. X            char *cp, *ccp;
  1290. X            cp = index(sep->se_service, '/');
  1291. X            if (cp == 0) {
  1292. X                syslog(LOG_ERR, "%s: no rpc version",
  1293. X                    sep->se_service);
  1294. X                goto more;
  1295. X            }
  1296. X            *cp++ = '\0';
  1297. X            sep->se_rpcversl =
  1298. X                sep->se_rpcversh = strtol(cp, &ccp, 0);
  1299. X            if (ccp == cp) {
  1300. X        badafterall:
  1301. X                syslog(LOG_ERR, "%s/%s: bad rpc version",
  1302. X                    sep->se_service, cp);
  1303. X                goto more;
  1304. X            }
  1305. X            if (*ccp == '-') {
  1306. X                cp = ccp + 1;
  1307. X                sep->se_rpcversh = strtol(cp, &ccp, 0); 
  1308. X                if (ccp == cp)
  1309. X                    goto badafterall;
  1310. X            }
  1311. X#else
  1312. X            syslog(LOG_ERR, "%s: rpc services not suported",
  1313. X                sep->se_service);
  1314. X            goto more;
  1315. X#endif RPC
  1316. X        }
  1317. X    }
  1318. X    arg = skip(&cp);
  1319. X    sep->se_wait = strcmp(arg, "wait") == 0;
  1320. X    if (sep->se_wait == 0 && sep->se_family == AF_PTY) {
  1321. X        syslog(LOG_ERR, "pty: only single threaded servers allowed: %s\n", sep->se_service);
  1322. X        sep->se_wait = 1;
  1323. X    }
  1324. X    sep->se_user = strdup(skip(&cp));
  1325. X    sep->se_server = strdup(skip(&cp));
  1326. X    if (strcmp(sep->se_server, "internal") == 0) {
  1327. X        register struct biltin *bi;
  1328. X
  1329. X        for (bi = biltins; bi->bi_service; bi++)
  1330. X            if (bi->bi_socktype == sep->se_socktype &&
  1331. X                strcmp(bi->bi_service, sep->se_service) == 0)
  1332. X                break;
  1333. X        if (bi->bi_service == 0) {
  1334. X            syslog(LOG_ERR, "internal service %s unknown\n",
  1335. X                sep->se_service);
  1336. X            goto more;
  1337. X        }
  1338. X        sep->se_bi = bi;
  1339. X        sep->se_wait = bi->bi_wait;
  1340. X    } else
  1341. X        sep->se_bi = NULL;
  1342. X    argc = 0;
  1343. X    for (arg = skip(&cp); cp; arg = skip(&cp))
  1344. X        if (argc < MAXARGV)
  1345. X            sep->se_argv[argc++] = strdup(arg);
  1346. X    while (argc <= MAXARGV)
  1347. X        sep->se_argv[argc++] = NULL;
  1348. X    return (sep);
  1349. X}
  1350. X
  1351. Xfreeconfig(cp)
  1352. X    register struct servtab *cp;
  1353. X{
  1354. X    int i;
  1355. X
  1356. X    if (cp->se_service)
  1357. X        free(cp->se_service);
  1358. X    if (cp->se_proto)
  1359. X        free(cp->se_proto);
  1360. X    if (cp->se_user)
  1361. X        free(cp->se_user);
  1362. X    if (cp->se_server)
  1363. X        free(cp->se_server);
  1364. X    for (i = 0; i < MAXARGV; i++)
  1365. X        if (cp->se_argv[i])
  1366. X            free(cp->se_argv[i]);
  1367. X}
  1368. X
  1369. Xchar *
  1370. Xskip(cpp)
  1371. X    char **cpp;
  1372. X{
  1373. X    register char *cp = *cpp;
  1374. X    char *start;
  1375. X
  1376. Xagain:
  1377. X    while (*cp == ' ' || *cp == '\t')
  1378. X        cp++;
  1379. X    if (*cp == '\0') {
  1380. X        int c;
  1381. X
  1382. X        c = getc(fconfig);
  1383. X        (void) ungetc(c, fconfig);
  1384. X        if (c == ' ' || c == '\t')
  1385. X            if (cp = nextline(fconfig))
  1386. X                goto again;
  1387. X        *cpp = (char *)0;
  1388. X        return ((char *)0);
  1389. X    }
  1390. X    start = cp;
  1391. X    while (*cp && *cp != ' ' && *cp != '\t')
  1392. X        cp++;
  1393. X    if (*cp != '\0')
  1394. X        *cp++ = '\0';
  1395. X    *cpp = cp;
  1396. X    return (start);
  1397. X}
  1398. X
  1399. Xchar *
  1400. Xnextline(fd)
  1401. X    FILE *fd;
  1402. X{
  1403. X    char *cp;
  1404. X
  1405. X    if (fgets(line, sizeof (line), fd) == NULL)
  1406. X        return ((char *)0);
  1407. X    cp = index(line, '\n');
  1408. X    if (cp)
  1409. X        *cp = '\0';
  1410. X    return (line);
  1411. X}
  1412. X
  1413. Xchar *
  1414. Xstrdup(cp)
  1415. X    char *cp;
  1416. X{
  1417. X    char *new;
  1418. X
  1419. X    if (cp == NULL)
  1420. X        cp = "";
  1421. X    new = malloc((unsigned)(strlen(cp) + 1));
  1422. X    if (new == (char *)0) {
  1423. X        syslog(LOG_ERR, "Out of memory.");
  1424. X        exit(-1);
  1425. X    }
  1426. X    (void)strcpy(new, cp);
  1427. X    return (new);
  1428. X}
  1429. X
  1430. Xsetproctitle(a, s)
  1431. X    char *a;
  1432. X    int s;
  1433. X{
  1434. X    int size;
  1435. X    register char *cp;
  1436. X    struct sockaddr_in sin;
  1437. X    char buf[80];
  1438. X
  1439. X    cp = Argv[0];
  1440. X    size = sizeof(sin);
  1441. X    if (getpeername(s, &sin, &size) == 0)
  1442. X        (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1443. X    else
  1444. X        (void) sprintf(buf, "-%s", a); 
  1445. X    strncpy(cp, buf, LastArg - cp);
  1446. X    cp += strlen(cp);
  1447. X    while (cp < LastArg)
  1448. X        *cp++ = ' ';
  1449. X}
  1450. X
  1451. Xlogpid()
  1452. X{
  1453. X    FILE *fp;
  1454. X
  1455. X    if ((fp = fopen(PIDFILE, "w")) != NULL) {
  1456. X        fprintf(fp, "%u\n", getpid());
  1457. X        (void)fclose(fp);
  1458. X    }
  1459. X}
  1460. X
  1461. X#ifdef sun
  1462. Xbump_nofile()
  1463. X{
  1464. X    struct rlimit rl;
  1465. X
  1466. X    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
  1467. X        return -1;
  1468. X    rl.rlim_cur = rl.rlim_max;
  1469. X    if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
  1470. X        return -1;
  1471. X    return 0;
  1472. X}
  1473. X#endif
  1474. X
  1475. X/*
  1476. X * Internet services provided internally by inetd:
  1477. X */
  1478. X#define    BUFSIZE    4096
  1479. X
  1480. X/* ARGSUSED */
  1481. Xecho_stream(s, sep)        /* Echo service -- echo data back */
  1482. X    int s;
  1483. X    struct servtab *sep;
  1484. X{
  1485. X    char buffer[BUFSIZE];
  1486. X    int i;
  1487. X
  1488. X    setproctitle(sep->se_service, s);
  1489. X    while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  1490. X        write(s, buffer, i) > 0)
  1491. X        ;
  1492. X    exit(0);
  1493. X}
  1494. X
  1495. X/* ARGSUSED */
  1496. Xecho_dg(s, sep)            /* Echo service -- echo data back */
  1497. X    int s;
  1498. X    struct servtab *sep;
  1499. X{
  1500. X    char buffer[BUFSIZE];
  1501. X    int i, size;
  1502. X    struct sockaddr sa;
  1503. X
  1504. X    size = sizeof(sa);
  1505. X    if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  1506. X        return;
  1507. X    (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  1508. X}
  1509. X
  1510. X/* ARGSUSED */
  1511. Xdiscard_stream(s, sep)        /* Discard service -- ignore data */
  1512. X    int s;
  1513. X    struct servtab *sep;
  1514. X{
  1515. X    char buffer[BUFSIZE];
  1516. X
  1517. X    setproctitle(sep->se_service, s);
  1518. X    while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
  1519. X            errno == EINTR)
  1520. X        ;
  1521. X    exit(0);
  1522. X}
  1523. X
  1524. X/* ARGSUSED */
  1525. Xdiscard_dg(s, sep)        /* Discard service -- ignore data */
  1526. X    int s;
  1527. X    struct servtab *sep;
  1528. X{
  1529. X    char buffer[BUFSIZE];
  1530. X
  1531. X    (void) read(s, buffer, sizeof(buffer));
  1532. X}
  1533. X
  1534. X#include <ctype.h>
  1535. X#define LINESIZ 72
  1536. Xchar ring[128];
  1537. Xchar *endring;
  1538. X
  1539. Xinitring()
  1540. X{
  1541. X    register int i;
  1542. X
  1543. X    endring = ring;
  1544. X
  1545. X    for (i = 0; i <= 128; ++i)
  1546. X        if (isprint(i))
  1547. X            *endring++ = i;
  1548. X}
  1549. X
  1550. X/* ARGSUSED */
  1551. Xchargen_stream(s, sep)        /* Character generator */
  1552. X    int s;
  1553. X    struct servtab *sep;
  1554. X{
  1555. X    register char *rs;
  1556. X    int len;
  1557. X    char text[LINESIZ+2];
  1558. X
  1559. X    setproctitle(sep->se_service, s);
  1560. X
  1561. X    if (!endring) {
  1562. X        initring();
  1563. X        rs = ring;
  1564. X    }
  1565. X
  1566. X    text[LINESIZ] = '\r';
  1567. X    text[LINESIZ + 1] = '\n';
  1568. X    for (rs = ring;;) {
  1569. X        if ((len = endring - rs) >= LINESIZ)
  1570. X            bcopy(rs, text, LINESIZ);
  1571. X        else {
  1572. X            bcopy(rs, text, len);
  1573. X            bcopy(ring, text + len, LINESIZ - len);
  1574. X        }
  1575. X        if (++rs == endring)
  1576. X            rs = ring;
  1577. X        if (write(s, text, sizeof(text)) != sizeof(text))
  1578. X            break;
  1579. X    }
  1580. X    exit(0);
  1581. X}
  1582. X
  1583. X/* ARGSUSED */
  1584. Xchargen_dg(s, sep)        /* Character generator */
  1585. X    int s;
  1586. X    struct servtab *sep;
  1587. X{
  1588. X    struct sockaddr sa;
  1589. X    static char *rs;
  1590. X    int len, size;
  1591. X    char text[LINESIZ+2];
  1592. X
  1593. X    if (endring == 0) {
  1594. X        initring();
  1595. X        rs = ring;
  1596. X    }
  1597. X
  1598. X    size = sizeof(sa);
  1599. X    if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  1600. X        return;
  1601. X
  1602. X    if ((len = endring - rs) >= LINESIZ)
  1603. X        bcopy(rs, text, LINESIZ);
  1604. X    else {
  1605. X        bcopy(rs, text, len);
  1606. X        bcopy(ring, text + len, LINESIZ - len);
  1607. X    }
  1608. X    if (++rs == endring)
  1609. X        rs = ring;
  1610. X    text[LINESIZ] = '\r';
  1611. X    text[LINESIZ + 1] = '\n';
  1612. X    (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  1613. X}
  1614. X
  1615. X/*
  1616. X * Return a machine readable date and time, in the form of the
  1617. X * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1618. X * returns the number of seconds since midnight, Jan 1, 1970,
  1619. X * we must add 2208988800 seconds to this figure to make up for
  1620. X * some seventy years Bell Labs was asleep.
  1621. X */
  1622. X
  1623. Xlong
  1624. Xmachtime()
  1625. X{
  1626. X    struct timeval tv;
  1627. X
  1628. X    if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1629. X        fprintf(stderr, "Unable to get time of day\n");
  1630. X        return (0L);
  1631. X    }
  1632. X    return (htonl((long)tv.tv_sec + 2208988800));
  1633. X}
  1634. X
  1635. X/* ARGSUSED */
  1636. Xmachtime_stream(s, sep)
  1637. X    int s;
  1638. X    struct servtab *sep;
  1639. X{
  1640. X    long result;
  1641. X
  1642. X    result = machtime();
  1643. X    (void) write(s, (char *) &result, sizeof(result));
  1644. X}
  1645. X
  1646. X/* ARGSUSED */
  1647. Xmachtime_dg(s, sep)
  1648. X    int s;
  1649. X    struct servtab *sep;
  1650. X{
  1651. X    long result;
  1652. X    struct sockaddr sa;
  1653. X    int size;
  1654. X
  1655. X    size = sizeof(sa);
  1656. X    if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  1657. X        return;
  1658. X    result = machtime();
  1659. X    (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  1660. X}
  1661. X
  1662. X/* ARGSUSED */
  1663. Xdaytime_stream(s, sep)        /* Return human-readable time of day */
  1664. X    int s;
  1665. X    struct servtab *sep;
  1666. X{
  1667. X    char buffer[256];
  1668. X    time_t time(), clock;
  1669. X    char *ctime();
  1670. X
  1671. X    clock = time((time_t *) 0);
  1672. X
  1673. X    (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1674. X    (void) write(s, buffer, strlen(buffer));
  1675. X}
  1676. X
  1677. X/* ARGSUSED */
  1678. Xdaytime_dg(s, sep)        /* Return human-readable time of day */
  1679. X    int s;
  1680. X    struct servtab *sep;
  1681. X{
  1682. X    char buffer[256];
  1683. X    time_t time(), clock;
  1684. X    struct sockaddr sa;
  1685. X    int size;
  1686. X    char *ctime();
  1687. X
  1688. X    clock = time((time_t *) 0);
  1689. X
  1690. X    size = sizeof(sa);
  1691. X    if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  1692. X        return;
  1693. X    (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1694. X    (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  1695. X}
  1696. X
  1697. X/*
  1698. X * print_service:
  1699. X *    Dump relevant information to stderr
  1700. X */
  1701. Xprint_service(action, sep)
  1702. X    char *action;
  1703. X    struct servtab *sep;
  1704. X{
  1705. X    fprintf(stderr,
  1706. X        "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
  1707. X        action, sep->se_service, sep->se_proto,
  1708. X        sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
  1709. X}
  1710. END_OF_FILE
  1711. if test 28032 -ne `wc -c <'munetd.c'`; then
  1712.     echo shar: \"'munetd.c'\" unpacked with wrong size!
  1713. fi
  1714. # end of 'munetd.c'
  1715. fi
  1716. if test -f 'setenv.c' -a "${1}" != "-c" ; then 
  1717.   echo shar: Will not clobber existing file \"'setenv.c'\"
  1718. else
  1719. echo shar: Extracting \"'setenv.c'\" \(2997 characters\)
  1720. sed "s/^X//" >'setenv.c' <<'END_OF_FILE'
  1721. X/*
  1722. X * Copyright (c) 1987 Regents of the University of California.
  1723. X * All rights reserved.
  1724. X *
  1725. X * Redistribution and use in source and binary forms are permitted
  1726. X * provided that: (1) source distributions retain this entire copyright
  1727. X * notice and comment, and (2) distributions including binaries display
  1728. X * the following acknowledgement:  ``This product includes software
  1729. X * developed by the University of California, Berkeley and its contributors''
  1730. X * in the documentation or other materials provided with the distribution
  1731. X * and in all advertising materials mentioning features or use of this
  1732. X * software. Neither the name of the University nor the names of its
  1733. X * contributors may be used to endorse or promote products derived
  1734. X * from this software without specific prior written permission.
  1735. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1736. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1737. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1738. X */
  1739. X
  1740. X#if defined(LIBC_SCCS) && !defined(lint)
  1741. Xstatic char sccsid[] = "@(#)setenv.c    5.4 (Berkeley) 6/1/90";
  1742. X#endif /* LIBC_SCCS and not lint */
  1743. X
  1744. X#include <stddef.h>
  1745. X#include <stdlib.h>
  1746. X
  1747. X/*
  1748. X * setenv --
  1749. X *    Set the value of the environmental variable "name" to be
  1750. X *    "value".  If rewrite is set, replace any current value.
  1751. X */
  1752. Xsetenv(name, value, rewrite)
  1753. X    register char *name, *value;
  1754. X    int rewrite;
  1755. X{
  1756. X    extern char **environ;
  1757. X    static int alloced;            /* if allocated space before */
  1758. X    register char *C;
  1759. X    int l_value, offset;
  1760. X    char *_findenv();
  1761. X
  1762. X    if (*value == '=')            /* no `=' in value */
  1763. X        ++value;
  1764. X    l_value = strlen(value);
  1765. X    if ((C = _findenv(name, &offset))) {    /* find if already exists */
  1766. X        if (!rewrite)
  1767. X            return(0);
  1768. X        if (strlen(C) >= l_value) {    /* old larger; copy over */
  1769. X            while (*C++ = *value++);
  1770. X            return(0);
  1771. X        }
  1772. X    }
  1773. X    else {                    /* create new slot */
  1774. X        register int    cnt;
  1775. X        register char    **P;
  1776. X
  1777. X        for (P = environ, cnt = 0; *P; ++P, ++cnt);
  1778. X        if (alloced) {            /* just increase size */
  1779. X            environ = (char **)realloc((char *)environ,
  1780. X                (size_t)(sizeof(char *) * (cnt + 2)));
  1781. X            if (!environ)
  1782. X                return(-1);
  1783. X        }
  1784. X        else {                /* get new space */
  1785. X            alloced = 1;        /* copy old entries into it */
  1786. X            P = (char **)malloc((size_t)(sizeof(char *) *
  1787. X                (cnt + 2)));
  1788. X            if (!P)
  1789. X                return(-1);
  1790. X            bcopy(environ, P, cnt * sizeof(char *));
  1791. X            environ = P;
  1792. X        }
  1793. X        environ[cnt + 1] = NULL;
  1794. X        offset = cnt;
  1795. X    }
  1796. X    for (C = name; *C && *C != '='; ++C);    /* no `=' in name */
  1797. X    if (!(environ[offset] =            /* name + `=' + value */
  1798. X        malloc((size_t)((int)(C - name) + l_value + 2))))
  1799. X        return(-1);
  1800. X    for (C = environ[offset]; (*C = *name++) && *C != '='; ++C);
  1801. X    for (*C++ = '='; *C++ = *value++;);
  1802. X    return(0);
  1803. X}
  1804. X
  1805. X/*
  1806. X * unsetenv(name) --
  1807. X *    Delete environmental variable "name".
  1808. X */
  1809. Xvoid
  1810. Xunsetenv(name)
  1811. X    char    *name;
  1812. X{
  1813. X    extern char **environ;
  1814. X    register char **P;
  1815. X    int offset;
  1816. X
  1817. X    while (_findenv(name, &offset))        /* if set multiple times */
  1818. X        for (P = &environ[offset];; ++P)
  1819. X            if (!(*P = *(P + 1)))
  1820. X                break;
  1821. X}
  1822. END_OF_FILE
  1823. if test 2997 -ne `wc -c <'setenv.c'`; then
  1824.     echo shar: \"'setenv.c'\" unpacked with wrong size!
  1825. fi
  1826. # end of 'setenv.c'
  1827. fi
  1828. echo shar: End of archive 1 \(of 1\).
  1829. cp /dev/null ark1isdone
  1830. MISSING=""
  1831. for I in 1 ; do
  1832.     if test ! -f ark${I}isdone ; then
  1833.     MISSING="${MISSING} ${I}"
  1834.     fi
  1835. done
  1836. if test "${MISSING}" = "" ; then
  1837.     echo You have the archive.
  1838.     rm -f ark[1-9]isdone
  1839. else
  1840.     echo You still need to unpack the following archives:
  1841.     echo "        " ${MISSING}
  1842. fi
  1843. ##  End of shell archive.
  1844. exit 0
  1845.