home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / pucc-install / part04 < prev    next >
Text File  |  1991-03-19  |  53KB  |  2,129 lines

  1. Subject:  v24i066:  Purdue software product installation system, Part04/07
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 573916ad 877ae86d 6b5c3b8c cb1503a1
  5.  
  6. Submitted-by: Kevin Braunsdorf <ksb@nostromo.cc.purdue.edu>
  7. Posting-number: Volume 24, Issue 66
  8. Archive-name: pucc-install/part04
  9.  
  10. Submitted-by: ksb@cc.purdue.edu (Kevin Braunsdorf)
  11. Archive-name: pucc-1b/part04
  12.  
  13. #!/bin/sh
  14. # This is part 04 of pucc-1b
  15. # ============= install.d/install.1l ==============
  16. if test ! -d 'install.d'; then
  17.     echo 'x - creating directory install.d'
  18.     mkdir 'install.d'
  19. fi
  20. if test -f 'install.d/install.1l' -a X"$1" != X"-c"; then
  21.     echo 'x - skipping install.d/install.1l (File already exists)'
  22. else
  23. echo 'x - extracting install.d/install.1l (Text)'
  24. sed 's/^X//' << 'Purdue' > 'install.d/install.1l' &&
  25. .\" $Id: install.1l,v 7.0 90/09/17 09:41:50 ksb Exp $
  26. .\" Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
  27. .\" 47907.  All rights reserved.
  28. .\"
  29. .\" Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
  30. .\"           Jeff Smith, jsmith@cc.purdue.edu, purdue!jsmith
  31. .\"
  32. .\" This software is not subject to any license of the American Telephone
  33. .\" and Telegraph Company or the Regents of the University of California.
  34. .\"
  35. .\" Permission is granted to anyone to use this software for any purpose on
  36. .\" any computer system, and to alter it and redistribute it freely, subject
  37. .\" to the following restrictions:
  38. .\"
  39. .\" 1. Neither the authors nor Purdue University are responsible for any
  40. .\"    consequences of the use of this software.
  41. .\"
  42. .\" 2. The origin of this software must not be misrepresented, either by
  43. .\"    explicit claim or by omission.  Credit to the authors and Purdue
  44. .\"    University must appear in documentation and sources.
  45. .\"
  46. .\" 3. Altered versions must be plainly marked as such, and must not be
  47. .\"    misrepresented as being the original software.
  48. .\"
  49. .\" 4. This notice may not be removed or altered.
  50. .\"
  51. .\" $Laser: ${tbl-tbl} %f | ${ltroff-ltroff} -man
  52. .\" $Compile: ${tbl-tbl} %f | ${nroff-nroff} -man | ${PAGER-${more-more}}
  53. .TH INSTALL 1L PUCC
  54. .SH NAME
  55. install \- update files or directories in a controlled environment
  56. .SH SYNOPSIS
  57. \fBinstall\fP [\-\fB1Dclnpqsv\fP] [\-\fBC\fP\fIchecklist\fP] [\-\fBH\fP\fIhardlinks\fP] [\-\fBS\fP\fIsymlinks\fP] [\-\fBg\fP\fIgroup\fP] [\-\fBm\fP\fImode\fP] [\-\fBo\fP\fIowner\fP] \fIfiles\fP \fIdestination\fP
  58. .sp 1
  59. \fBinstall\fP \-\fBd\fP [\-\fBhnqrv\fP] [\-\fBC\fP\fIchecklist\fP] [\-\fBg\fP\fIgroup\fP] [\-\fBm\fP\fImode\fP] [\-\fBo\fP\fIowner\fP] \fIdirectory\fP
  60. .sp 1
  61. \fBinstall\fP \-[\fBhV\fP] [\-\fBC\fP\fIchecklist\fP]
  62. .sp 1
  63. \fBinstall\fP \-\fBR\fP [\-\fB1dlnqsv\fP] [\-\fBC\fP\fIchecklist\fP] [\-\fBH\fP\fIhardlinks\fP] [\-\fBS\fP\fIsymlinks\fP] [\-\fBg\fP\fIgroup\fP] [\-\fBm\fP\fImode\fP] [\-\fBo\fP\fIowner\fP] \fIdestination\fP
  64. .SH DESCRIPTION
  65. .PP
  66. .I Install
  67. is a tool for updating system files in a controlled environment.
  68. The design philosophy of
  69. .I install
  70. is to automate the installation process and put
  71. it as much out of reach of human carelessness as possible, while
  72. providing a flexible, easy to use tool.
  73. .I Install
  74. provides the following features:
  75. .IP \(bu
  76. .I Install
  77. increases system security by providing a controlled installation
  78. environment.  It checks the actions of the superuser against a
  79. configuration file that you build (either by hand or using
  80. .IR instck (1L)),
  81. and can prevent grievous mistakes such as installing a shell setuid
  82. to a privileged user, or installing a world\(hywritable password file.
  83. An appropriate configuration file can guarantee that files are
  84. installed with correct owner, group and mode, that
  85. .IR strip (1)
  86. is run on binaries and 
  87. .IR ranlib (1)
  88. is run on libraries.
  89. Regardless of whether you create a configuration file,
  90. .I install
  91. warns you of many possible errors, unless you make it quiet
  92. with its
  93. .B \-q
  94. option.  For instance, if you install
  95. a new version of the
  96. .IR ex (1)
  97. editor and forget to update its links,
  98. .I install
  99. will notice the extra links to the existing version and warn
  100. you that you might be making a mistake.
  101. .IP \(bu
  102. Installed files do not overwrite current versions.  The current version
  103. is backed up to a subdirectory of its dot directory (named \*(lqOLD\*(rq by
  104. default), where it may be easily
  105. re\(hyinstalled in the case of an unforeseen bug.  The companion program
  106. .IR purge (1L)
  107. removes these backed\(hyup files after a user\(hyspecified interval.
  108. By default, if you repeatedly install new versions of a file,
  109. .I install
  110. creates a series of backups, providing a primitive form of version
  111. control.
  112. .IP \(bu
  113. .I Install
  114. increases accountability by logging the actions of the superuser.
  115. This makes it easier to track down errors after the fact.
  116. .IP \(bu
  117. .I Install
  118. simplifies Makefiles by allowing you to combine operations that
  119. would require several steps into a single one (e.g., you can specify
  120. in a single command line a file's ownership, group, mode, whether to run
  121. .IR strip (1)
  122. or
  123. .IR ranlib (1),
  124. and which hard or soft links should be made).
  125. .IP \(bu
  126. Despite its power and potential complexity,
  127. .I install
  128. is easy to use interactively because it intuits appropriate
  129. installation parameters for you, either by using those associated with
  130. an existing file, or its compilation\(hydependent defaults.  In most
  131. cases you do not have to specify a file's owner, group, or mode unless
  132. you want them to be different from an existing file or the
  133. compilation\(hydependent defaults.
  134. Typical interactive usage is simply \*(lqinstall file destination.\*(rq
  135. .IP \(bu
  136. .I Install
  137. is as careful as it can be to complete an installation once it is
  138. begun.  There is a point in the code where
  139. .IR unlink (2)
  140. and
  141. .IR rename (2)
  142. must be executed in close succession, and that is the only window in
  143. which a system crash or a signal might leave system files in
  144. an inconsistent state (unfortunately, this is not true under operating
  145. systems that do not provide an atomic
  146. .IR rename (2)
  147. system call).
  148. This is true even when
  149. .I install
  150. must copy files across file system boundaries.
  151. .IP \(bu
  152. .I Install
  153. may also be used to remove (de\(hyinstall) files in a controlled manner.
  154. .IP \(bu
  155. Finally,
  156. .I install
  157. currently runs on a variety of architectures and operating systems
  158. and is easy to port to new platforms.
  159. .SH USAGE
  160. .SS Terminology
  161. .PP
  162. The user specifies one or more
  163. .I files
  164. to install, and a
  165. .IR destination ,
  166. which may be either a full or relative pathname ending
  167. in a file name or an existing directory name (if the
  168. directory does not exist,
  169. .I install
  170. thinks you mean to create a new file).
  171. The special name \*(lq\-\*(rq may be used for the
  172. .I file
  173. argument to indicate stdin (see EXAMPLES).  In this case,
  174. .I destination
  175. .B must not
  176. be a directory, since
  177. .I install
  178. cannot guess the name the file should have when installed.
  179. .PP
  180. Because the user may specify more than one
  181. .IR files ,
  182. and
  183. .I destination
  184. may be an existing directory or a file which may or may not
  185. exist,
  186. .I install
  187. must also internally keep track of a
  188. .I destdir
  189. (\*(lqdestination directory\*(rq, i.e., the directory in which to
  190. place the file to install), and a
  191. .IR target
  192. (the full pathname that each file to install
  193. will have when it is installed in
  194. .IR destdir ).
  195. The
  196. .I target
  197. and
  198. .I destdir
  199. are constructed from the
  200. .I files
  201. and
  202. .I destination
  203. arguments as described below.
  204. .PP
  205. For each name in
  206. .IR files ,
  207. .I install
  208. determines a
  209. .I target
  210. name as follows:
  211. If
  212. .I destination
  213. is an existing directory,
  214. .I install
  215. catenates the last component of
  216. .I file
  217. to
  218. .I destination
  219. to arrive at the
  220. .I target
  221. name.  If
  222. .I destination
  223. does not exist or is an existing file,
  224. .I install
  225. takes
  226. .I destination
  227. to be the
  228. .IR target .
  229. In the latter case
  230. .I destdir
  231. is simply
  232. .I destination
  233. minus its last component.
  234. If this reduction leaves
  235. .I destdir
  236. empty then it is set to \*(lq.\*(rq.
  237. (E.g., if
  238. .I destination
  239. were
  240. .I /etc/motd
  241. then
  242. .I destdir
  243. would be
  244. .IR /etc ,
  245. but if
  246. .I destination
  247. were just
  248. .I motd
  249. then
  250. .I destdir
  251. would be \*(lq.\*(rq.)
  252. N.B.:  If more than one
  253. .I files
  254. are specified,
  255. .I destination
  256. .B must
  257. be an existing directory.
  258. .PP
  259. Examples are the easiest way to clarify this terminology.
  260. .RS
  261. .sp 1
  262. In the command \*(lqinstall motd /etc/motd\*(rq:
  263. .sp 1
  264. .RS
  265. .TS
  266. l l .
  267. file:    motd
  268. destination:    /etc/motd
  269. destdir:    /etc
  270. target:    /etc/motd
  271. .TE
  272. .RE
  273. .sp 1
  274. In the command \*(lqinstall motd /etc\*(rq:
  275. .sp 1
  276. .RS
  277. .TS
  278. l l .
  279. file:    motd
  280. destination:    /etc
  281. destdir:    /etc
  282. target:    /etc/motd
  283. .TE
  284. .RE
  285. .sp 1
  286. In the command sequence \*(lqcd /etc; install motd.new motd\*(rq:
  287. .sp 1
  288. .RS
  289. .TS
  290. l l .
  291. file:    motd.new
  292. destination:    motd
  293. destdir:    . (dot)
  294. target:    ./motd
  295. .TE
  296. .RE
  297. .RE
  298. .sp 1
  299. .SS Installation Parameters
  300. .PP
  301. If the file permissions, ownership or group ownership are not specified on
  302. the command line and
  303. .I target
  304. exists,
  305. .I install
  306. duplicates its group, ownership, and mode.
  307. Otherwise, if the
  308. .I target
  309. doesn't exist and the invoker is the superuser,
  310. .I install
  311. uses its compilation\(hydependent defaults.
  312. Otherwise,
  313. .I install
  314. uses the effective uid, the effective gid,
  315. and a compilation\(hydependent mode.
  316. .I Install
  317. may also be configured to inherit the mode and ownerships
  318. from the
  319. .IR destdir .
  320. (Use the
  321. .B \-V
  322. option to view the compilation\(hydependent defaults.)
  323. .PP
  324. Note:
  325. .I install
  326. can only change ownership if invoked by the superuser;
  327. however, any user may specify a different group
  328. as long as the group is allowed by
  329. .IR chgrp (1).
  330. .SS Method of Operation
  331. .PP
  332. .I Install
  333. first checks the proposed owner, group, and mode against the
  334. configuration file.  It also checks whether the
  335. .I target
  336. should have
  337. .IR strip (1)
  338. or
  339. .IR ranlib (1)
  340. run on it after installation. 
  341. .I Install
  342. aborts if it finds discrepancies between the configuration
  343. file and the proposed installation parameters.  (If necessary,
  344. you can override the configuration file
  345. with \*(lq\fB\-C\fP \fI/dev/null\fP.\*(rq)
  346. .PP
  347. .I Install
  348. then looks for an existing
  349. .I target
  350. and backs it up to a subdirectory of
  351. .I destdir
  352. named \*(lqOLD\*(rq, which
  353. .I install
  354. will create if it doesn't exist.
  355. The backup is actually just a hard link to the existing
  356. .IR target .
  357. (If a backup file of the same name already exists in \*(lqOLD\*(rq,
  358. .I install
  359. first renames it by appending its process id).
  360. For security reasons,
  361. .I install
  362. drops setuid and setgid bits when files are moved to the \*(lqOLD\*(rq
  363. directory.
  364. After backing up an existing
  365. .IR target ,
  366. .I install
  367. temporarily moves
  368. .I file
  369. to
  370. .IR destdir/OLD/random-name .
  371. This step is taken to ensure that both
  372. .I file
  373. and
  374. .I target
  375. are in the same file system so that
  376. .IR rename (2)
  377. may be used for the final installation.  This reduces the window
  378. in which files might be left in an inconsistent state due to a
  379. system crash or signal.  Consequently the \*(lqOLD\*(rq
  380. subdirectory must not be a file system mount point, since the
  381. .IR rename (2)
  382. would fail.
  383. .PP
  384. .I Install
  385. then unlinks the existing
  386. .I target
  387. (leaving the backup) and renames
  388. .IR destdir/OLD/random-name
  389. to
  390. .IR target .
  391. .PP
  392. Next
  393. .I install
  394. updates any hard links and soft (symbolic) links
  395. given under the
  396. .B \-H
  397. or
  398. .B \-S
  399. options.  All links point at the
  400. installed
  401. .IR target .
  402. Existing symbolic links which point to the
  403. correct file are left unchanged, otherwise removed and
  404. replaced with the correct spelling.  Existing correct hard links
  405. are unlinked and replaced, without a
  406. backup.  Links which point to a file other than the
  407. .I target
  408. are backed up to \*(lqOLD\*(rq and linked.
  409. .I Install
  410. prints a warning in this case.
  411. .SH OPTIONS
  412. .TP
  413. .B \-1
  414. After a successful installation
  415. .I install
  416. removes any previous
  417. backup in \*(lqOLD\*(rq.
  418. Thus
  419. .I install
  420. will keep exactly one previous revision of
  421. the installed file.
  422. .TP
  423. .B \-c
  424. Do not unlink the
  425. .IR files .
  426. .TP
  427. .BI \-C checkfile
  428. Search 
  429. .I checkfile
  430. for an expression that matches the
  431. .IR target .
  432. If
  433. .I install
  434. finds such an expression it will check the proposed modes (etc.)
  435. against those listed in the checkfile; any differences cause
  436. .I install
  437. to abort the installation.
  438. This mechanism is provided to protect the superuser from installing,
  439. for instance, the shell setuid root, as in:
  440. .br
  441. .sp 1
  442. .in 1.5i
  443. install \-m7555 \-o root \-g wheel sh /bin
  444. .sp 1
  445. .in -.5i
  446. .br
  447. (note the extra \*(lq5\*(rq).
  448. See
  449. .IR install.cf (5L)
  450. and
  451. .IR instck (1L).
  452. .TP
  453. .BI \-d
  454. Build a directory rather than a plain file.
  455. If the directory is an OLD directory it is built with appropriate modes
  456. (see
  457. .B \-V
  458. below).
  459. .TP
  460. .B \-D
  461. Don't back up an existing
  462. .I target
  463. (the \*(lqDestroy\*(rq option).
  464. This is useful when a trivially correctable problem such as a
  465. spelling error in a print statement is found in a recently installed
  466. product, or when the
  467. .I target
  468. can be regenerated easily and is installed frequently.  Sites that
  469. do not wish to keep backups but still want to take advantage of the
  470. checkfile could set this option in the environment.
  471. .TP
  472. .BI \-g group
  473. Install the file with group ownership
  474. .IR group .
  475. If no
  476. .B \-g
  477. option is given
  478. .I install
  479. will decide the group to use:
  480. .br
  481. .in 1.5i
  482. \(bu if there is an existing
  483. .I target
  484. use its group
  485. .br
  486. \(bu if we are the superuser use a compilation\(hydependent group
  487. .br
  488. \(bu else use the effective group id
  489. .TP
  490. .in -.5i
  491. .B \-h
  492. Print a summary of
  493. .IR install 's
  494. usage (the \*(lqhelp\*(rq option).
  495. .TP
  496. .BI \-H hardlinks
  497. Specify a colon separated list of hard links
  498. that should be made to the
  499. .I target
  500. after it is installed.
  501. (See EXAMPLES below.)
  502. .TP
  503. .BI \-l
  504. Run
  505. .IR ranlib ( 1 )
  506. on the installed
  507. .IR targets .
  508. Under System V this option has no significance, but
  509. .B must
  510. be given to pass the default checkfile
  511. (see
  512. .IR install.cf (5L)).
  513. This allows Makefiles to work under all versions of UNIX.
  514. .TP
  515. .BI \-m mode
  516. Install the file with permissions
  517. .IR mode .
  518. .I Mode
  519. may be given in either octal mode or
  520. in the symbolic form used by
  521. .IR ls (1)
  522. (e.g., \*(lq755\*(rq) is equivalent to \*(lqrwxr-xr-x\*(rq).
  523. If the
  524. .B \-m
  525. option is not given,
  526. .I install
  527. will decide the mode to use:
  528. .br
  529. .in 1.5i
  530. \(bu if there is an existing
  531. .I target
  532. use its mode
  533. .br
  534. \(bu if we are the superuser use a compilation\(hydependent mode
  535. .br
  536. \(bu else use a compilation\(hydependent user mode
  537. .in -.5i
  538. .TP
  539. .B \-n
  540. Give an approximate execution trace by printing the (almost) equivalent
  541. shell commands, but don't do anything.
  542. This is useful for debugging
  543. .I install
  544. or seeing what a
  545. difficult command line would do if you ran it.
  546. .TP
  547. .BI \-o owner
  548. Change ownership of
  549. .I file
  550. to
  551. .I owner
  552. (superuser only).
  553. If no
  554. .B \-o
  555. option is given
  556. .I install
  557. will decide the owner to use:
  558. .br
  559. .in 1.5i
  560. \(bu if there is an existing
  561. .I target
  562. use its owner
  563. .br
  564. \(bu if we are the superuser use a compilation\(hydependent owner
  565. .br
  566. \(bu else use our effective uid
  567. .TP
  568. .in -.5i
  569. .B \-p
  570. Preserve the time stamp of
  571. .I files
  572. in
  573. .IR targets .
  574. .TP
  575. .B \-q
  576. Normally
  577. .I install
  578. informs you about a variety of possible errors.  This option
  579. turns off that behavior and is not recommended except for
  580. special circumstances.  Caveat emptor.
  581. .TP
  582. .B \-r
  583. Under
  584. .B \-d
  585. build all intervening directories between \*(lq/\*(rq
  586. and
  587. .IR destination.
  588. .TP
  589. .B \-R
  590. Remove (de\(hyinstall) a file by moving it into the OLD
  591. subdirectory.  A temporary shell script is created to replace
  592. the
  593. .IR target ,
  594. installed (which removes the existing
  595. .I target
  596. to \*(lqOLD\*(rq), and removed.
  597. .TP
  598. .B \-s
  599. Run
  600. .IR strip (1)
  601. on the installed
  602. .IR targets .
  603. .TP
  604. .BI \-S symlinks
  605. Specify a colon separated list of symbolic links that
  606. .I install
  607. should
  608. point at the installed file.  (See EXAMPLES below.)
  609. .TP
  610. .B \-v
  611. Be verbose.  Run
  612. .IR ls (1)
  613. on the backed up file and the
  614. .IR target .
  615. Notify the user of all side effects of this installation.
  616. .TP
  617. .B \-V
  618. View
  619. .IR install 's
  620. version and compilation\(hydependent owner, group and mode tables.
  621. .SH EXAMPLES
  622. .TP
  623. install motd /etc
  624. Install
  625. .I motd
  626. as
  627. .IR /etc/motd .
  628. If
  629. .I /etc/motd
  630. exists move it to
  631. .I /etc/OLD/motd
  632. and duplicate its
  633. ownership, group and mode; otherwise,
  634. use defaults.  Create the directory
  635. .I /etc/OLD
  636. if it does not exist.
  637. .TP
  638. install \-c1 \-m 755 foo.sh /etc/foo
  639. Install
  640. .IR foo.sh .
  641. as
  642. .IR /etc/foo .
  643. Do not unlink
  644. .I foo.sh
  645. after the installation.  Set permissions appropriate for a shell script on
  646. .IR /etc/foo .
  647. If
  648. .I /etc/OLD/foo
  649. exists, overwrite it instead of moving it to a new name (i.e., retain a
  650. single backup of
  651. .I /etc/foo
  652. in
  653. .IR /etc/OLD ).
  654. .TP
  655. install foo bar baz /usr/lib
  656. Install the files
  657. .IR foo ,
  658. .I bar
  659. and
  660. .I baz
  661. as
  662. .IR /usr/lib/foo ,
  663. .IR /usr/lib/bar ,
  664. and
  665. .IR /usr/lib/baz .
  666. Use the modes of the existing files or defaults.
  667. .TP
  668. install \-vsm6751 \-oroot \-gkmem sendmail /usr/lib
  669. Install
  670. .I sendmail
  671. as
  672. .IR /usr/lib/sendmail ,
  673. owned by root, grouped to kmem, and with
  674. the setuid and setgid permission bits set.
  675. Strip
  676. .I /usr/lib/sendmail
  677. after its installation and be verbose.
  678. .TP
  679. install \-d \-m \-rwxrwxrwt /tmp
  680. Build the directory
  681. .I /tmp
  682. with the default owner and group,
  683. mode 777, and with the \*(lqsticky\*(rq bit set.
  684. .TP
  685. install \-c \-m1755 \-Hview:vi:edit:e:/usr/bin/ex a.out /usr/ucb/ex
  686. Install the
  687. .I ex
  688. editor with all of its hard links
  689. .RI ( /usr/ucb/view ,
  690. .IR /usr/ucb/vi ,
  691. .IR /usr/ucb/edit ,
  692. .IR /usr/ucb/e ,
  693. .RI and /usr/bin/ex ).
  694. Replacing
  695. .B \-H
  696. with
  697. .B \-S
  698. would cause
  699. .I install
  700. to build symbolic links on machines which support them.
  701. .TP
  702. install \-d \-r /usr/local/lib/mk
  703. Recursively build any and all of the directories
  704. .IR /usr ,
  705. .IR /usr/local ,
  706. .IR /usr/local/lib ,
  707. and
  708. .I /usr/local/lib/mk
  709. that do not already exist.  Silently do nothing if they
  710. already exist (useful in Makefiles).
  711. .TP
  712. install \-V
  713. Output the version of install and a table of compiled in defaults.
  714. Output when run as the superuser might look similar to this,
  715. depending on the compilation defaults:
  716. .RS
  717. .TS
  718. l s s
  719. l s s
  720. l l l.
  721. install: version: $\&Id: main.c,v 6.7 64/02/15 16:21:41 ksb Exp $
  722. install: configuration file: /usr/local/etc/install.cf
  723. install: syslog facility: 144
  724. install: superuser defaults:
  725. install: owner is file=root    dir=root    OLD=root
  726. install: group is file=binary    dir=binary    OLD=binary
  727. install: mode is  file=0755    dir=0755    OLD=inherited
  728. .TE
  729. .RE
  730. .TP
  731. rsh some.other.host install \- /etc/motd < motd.some.other.host
  732. This example shows a way to use \*(lq\-\*(rq to advantage.  It is
  733. often useful when
  734. .IR rdist (1)
  735. is overkill or otherwise inappropriate.  For instance, if you had
  736. a Makefile that generated files named
  737. .IR host1.motd ,
  738. .IR host2.motd ,
  739. .IR host3.motd ,
  740. etc., and wanted to install them on those hosts, you could do
  741. something like this:
  742. .sp 1
  743. .nf
  744. .na
  745. .KS
  746. .RS
  747. for host in host1 host2 host3; do
  748. .RS
  749. rsh $host install \- /etc/motd < $host.motd
  750. .RE
  751. done
  752. .KE
  753. .RE
  754. .fi
  755. .ad
  756. .sp 1
  757. .SH DIAGNOSTICS
  758. .KS
  759. .PP
  760. Unless made quiet by
  761. .BR \-q ,
  762. .I install
  763. will warn the installer if:
  764. .RS
  765. .br
  766. \(bu the owner, group, or mode changes
  767. .br
  768. \(bu the setuid, setgid, or sticky bits change
  769. .br
  770. \(bu a setuid program is loaded with the \*(lq#!\*(rq magic number
  771. .br
  772. \(bu \fItarget\fP does not exist (this is a prophylactic against
  773. typographical errors\(emsee CAVEATS below)
  774. .KE
  775. .RE
  776. .PP
  777. .KS
  778. .I Install
  779. will abort the installation if:
  780. .RS
  781. .br
  782. \(bu
  783. .I install
  784. cannot make a backup of an existing
  785. .I target
  786. .br
  787. \(bu a setuid program\'s owner was not specified with the mode
  788. .br
  789. \(bu a setgid program\'s group was not specified with the mode
  790. .br
  791. \(bu the specified owner, group, or mode failed to match the checkfile
  792. .br
  793. \(bu the superuser installs a setuid program that is not in the checkfile
  794. (this is a compile time option)
  795. .RE
  796. .KE
  797. .SH ENVIRONMENT
  798. .PP
  799. The environment variable
  800. .B INSTALL
  801. may be used to
  802. set command line options.
  803. Such options are read before any explicit command line options, e.g.
  804. .br
  805. .RS
  806. .sp 1
  807. INSTALL=-v ; export INSTALL
  808. .sp 1
  809. .RE
  810. .br
  811. will turn on \*(lqverbose\*(rq mode for all subsequent
  812. invocations of
  813. .IR install .
  814. .SH BUGS
  815. .PP
  816. .I Install
  817. does not use file locking, so it's possible for two competing
  818. .I install
  819. processes to lose data.
  820. .PP
  821. The trace option
  822. .RB ( \-n )
  823. doesn't always show exactly what
  824. .I install
  825. would do.  It will show OLD directories being made several times, and
  826. inherited modes don't propagate correctly under
  827. .BR \-drn .
  828. .SH CAVEATS
  829. .PP \(bu
  830. .I Install
  831. will not build character special files.
  832. Use
  833. .IR mknod (8)
  834. instead.
  835. .PP
  836. If /bin doesn't exist, the command:
  837. .sp 1
  838. .RS
  839. install ls /bin
  840. .RE
  841. .sp 1
  842. will make
  843. .I /bin
  844. be a copy of the binary
  845. .IR ls .
  846. This is an unavoidable consequence of allowing the
  847. .I destination
  848. to be a directory.
  849. You can avoid this by
  850. using \*(lqinstall \-d \fIdirectory\fP\*(rq in Makefiles to ensure
  851. that destination directories exist, e.g.,
  852. .sp 1
  853. .nf
  854. .na
  855. .RS
  856. install: product
  857. .RS
  858. install -d /bin
  859. install product /bin
  860. .RE
  861. .RE
  862. .fi
  863. .ad
  864. .sp 1
  865. .I Install
  866. does nothing  and exits normally if the directory already exists,
  867. so it's safe to include lines like this in your Makefiles.
  868. You can also use
  869. .IR instck (1L)
  870. to ensure that all system
  871. directories are built correctly.
  872. .PP \(bu
  873. .I Install
  874. can cover up mistakes of omission in Makefiles by copying the modes
  875. on a previously installed target.
  876. For example, the invocation of
  877. .I install
  878. in a Makefile might not specify that the
  879. .I destination
  880. should be setuid root, but
  881. as long as the
  882. .I target
  883. existed
  884. .I install
  885. would hide the error by
  886. copying the modes of the existing
  887. .IR target .
  888. The problem in the Makefile would not be found unless the
  889. .I target
  890. were removed prior to installation.
  891. Use
  892. .IR instck (1L)
  893. to generate a configuration file to avoid this problem.
  894. .PP \(bu
  895. .I Install
  896. and
  897. .IR purge (1L)
  898. assume that they own the file namespace in the \*(lqOLD\*(rq
  899. subdirectories.  If other programs create, modify or delete
  900. files in the \*(lqOLD\*(rq subdirectories, they will probably
  901. collide with one of
  902. .I install
  903. or
  904. .IR purge (1L)
  905. eventually.
  906. .SH FILES
  907. .TS
  908. l l.
  909. /usr/local/lib/install.cf    the default check list file
  910. .../OLD/#inst*    temporary files made for installations
  911. .../OLD/#bogus*    links made to running binaries to avoid ETXTBSY
  912. .../OLD/*    copies of previously installed files
  913. .TE
  914. .SH AUTHORS
  915. Kevin Braunsdorf, Purdue University Computing Center (ksb@cc.purdue.edu)
  916. .br
  917. Jeff Smith, Purdue University Computing Center (jsmith@cc.purdue.edu)
  918. .br
  919. Copyright \*(co 1990 Purdue Research Foundation.  All rights reserved.
  920. .SH "SEE ALSO"
  921. chgrp(1), instck(1L), ls(1), make(1), ranlib(1), strip(1),
  922. intro(2),
  923. syslog(3),
  924. install.cf(5L),
  925. chown(8), mknod(8), purge(8L)
  926. Purdue
  927. chmod 0444 install.d/install.1l ||
  928. echo 'restore of install.d/install.1l failed'
  929. Wc_c="`wc -c < 'install.d/install.1l'`"
  930. test 21337 -eq "$Wc_c" ||
  931.     echo 'install.d/install.1l: original size 21337, current size' "$Wc_c"
  932. fi
  933. # ============= purge/purge.c ==============
  934. if test ! -d 'purge'; then
  935.     echo 'x - creating directory purge'
  936.     mkdir 'purge'
  937. fi
  938. if test -f 'purge/purge.c' -a X"$1" != X"-c"; then
  939.     echo 'x - skipping purge/purge.c (File already exists)'
  940. else
  941. echo 'x - extracting purge/purge.c (Text)'
  942. sed 's/^X//' << 'Purdue' > 'purge/purge.c' &&
  943. /*
  944. X * a C version of purge(8L)                        (ksb)
  945. X *
  946. X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
  947. X * 47907.  All rights reserved.
  948. X *
  949. X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
  950. X *
  951. X * This software is not subject to any license of the American Telephone
  952. X * and Telegraph Company or the Regents of the University of California.
  953. X *
  954. X * Permission is granted to anyone to use this software for any purpose on
  955. X * any computer system, and to alter it and redistribute it freely, subject
  956. X * to the following restrictions:
  957. X *
  958. X * 1. Neither the authors nor Purdue University are responsible for any
  959. X *    consequences of the use of this software.
  960. X *
  961. X * 2. The origin of this software must not be misrepresented, either by
  962. X *    explicit claim or by omission.  Credit to the authors and Purdue
  963. X *    University must appear in documentation and sources.
  964. X *
  965. X * 3. Altered versions must be plainly marked as such, and must not be
  966. X *    misrepresented as being the original software.
  967. X *
  968. X * 4. This notice may not be removed or altered.
  969. X *
  970. X *
  971. X * The old shell version of purge suffered from 4 problems:
  972. X *
  973. X * 1\ it used the -ctime option to find that is local to PUCC
  974. X *
  975. X * 2\ it didn't handle symbolic links correctly
  976. X *
  977. X * 3\ it didn't handle error conditions well (st_nlink > 1)
  978. X *
  979. X * 4\ it was not useful to general users
  980. X *
  981. X * READ THIS!  N.B. if you want to change purge:
  982. X *
  983. X *    Do *NOT* change purge to delete empty OLD dirs.  This will race
  984. X *    with install and cause install the fail. (As is won't build the
  985. X *    OLD dir, the dir will go away, install will try to build a link
  986. X *    in it and fail.)
  987. X */
  988. #include <sys/param.h>
  989. #include <sys/types.h>
  990. #include <sys/stat.h>
  991. #include <sys/file.h>
  992. #include <sys/time.h>
  993. X
  994. #include <pwd.h>
  995. #include <grp.h>
  996. #include <errno.h>
  997. #include <ctype.h>
  998. #include <stdio.h>
  999. X
  1000. #include "configure.h"
  1001. #include "install.h"
  1002. #include "purge.h"
  1003. #include "filedup.h"
  1004. #include "main.h"
  1005. X
  1006. #if BSDDIR
  1007. #include <sys/dir.h>
  1008. #else
  1009. #include <ndir.h>
  1010. #endif
  1011. X
  1012. #if !defined(ENAMETOOLONG)
  1013. #define ENAMETOOLONG E2BIG
  1014. #endif
  1015. X
  1016. extern char *malloc(), *realloc(), *strcpy(), *strrchr();
  1017. X
  1018. #ifndef lint
  1019. static char copyright[] =
  1020. "@(#) Copyright 1990 Purdue Research Foundation.\nAll rights reserved.\n";
  1021. #endif
  1022. X
  1023. static time_t
  1024. X    tCutOff,        /* the last install time we keep    */
  1025. X    tCopyKeep;        /* last temp copy to keep        */
  1026. static char acRoot[] =        /* could be "root" "lroot" or "0"    */
  1027. X    DEFDIROWNER;
  1028. static char acOld[] =        /* the name of our OLD dirs        */
  1029. X    OLDDIR;
  1030. static char acBogus[] =        /* component key for busy links        */
  1031. X    TMPBOGUS;
  1032. static char acCopy[] =        /* component key for temp copies    */
  1033. X    TMPINST;
  1034. static FILEDUPS FDLinks;    /* hard links database            */
  1035. static int
  1036. X    bHaveRoot,        /* are effective uid lets us be root    */
  1037. X    iCopy,            /* strlen of acCopy            */
  1038. X    iBogus;            /* strlen of acBogus            */
  1039. X
  1040. #define LSTAT    lstat
  1041. X
  1042. struct {
  1043. X    int size;        /* the size of the uid array itself    */
  1044. X    int count;        /* number of ids we are keeping        */
  1045. X    uid_t *puids;        /* the uid array we are keeping        */
  1046. X    char **ppclogins;    /* the login names we found        */
  1047. } ids = {0, 0, (uid_t *)0};
  1048. X
  1049. /* this routine should check for all the OLD dir owners            (ksb)
  1050. X * (like `root', `news', `ingress', etc)
  1051. X */
  1052. int
  1053. isSysId(uid)
  1054. uid_t uid;
  1055. {
  1056. X    register int j;
  1057. X
  1058. X    if (fAnyOwner)
  1059. X        return 1;
  1060. X    for (j = 0; j < ids.count; ++j) {
  1061. X        if (ids.puids[j] == uid) {
  1062. X            return 1;
  1063. X        }
  1064. X    }
  1065. X    return 0;
  1066. }
  1067. X
  1068. /*
  1069. X * is a string all digits                        (ksb)
  1070. X */
  1071. int
  1072. AllDigits(pcTemp)
  1073. char *pcTemp;
  1074. {
  1075. X    for (; '\000' != *pcTemp; ++pcTemp) {
  1076. X        if (!isdigit(*pcTemp))
  1077. X            return 0;
  1078. X    }
  1079. X    return 1;
  1080. }
  1081. X
  1082. /*
  1083. X * this routine adds a new valid OLD dir owner to the list        (ksb)
  1084. X */
  1085. int
  1086. AddHer(pcLogin)
  1087. char *pcLogin;
  1088. {
  1089. X    register int j;
  1090. X    register struct passwd *pwdAdd;
  1091. X
  1092. X    if (AllDigits(pcLogin)) {
  1093. X        if ((struct passwd *)0 == (pwdAdd = getpwuid(atoi(pcLogin)))) {
  1094. X            fprintf(stderr, "%s: getpwuid: %s: %s\n", progname, pcLogin, strerror(errno));
  1095. X            return 1;
  1096. X        }
  1097. X    } else if ((struct passwd *)0 == (pwdAdd = getpwnam(pcLogin))) {
  1098. X        fprintf(stderr, "%s: getpwname: %s: %s\n", progname, pcLogin, strerror(errno));
  1099. X        return 1;
  1100. X    }
  1101. X    if (ids.size < ids.count+1) {
  1102. X        ids.size += 8;
  1103. X        if ((uid_t *)0 == ids.puids) {
  1104. X            ids.puids = (uid_t *)malloc(ids.size*sizeof(uid_t));
  1105. X        } else {
  1106. X            ids.puids = (uid_t *)realloc((char *)ids.puids, ids.size*sizeof(uid_t));
  1107. X        }
  1108. X        if ((char **)0 == ids.ppclogins) {
  1109. X            ids.ppclogins = (char **)malloc(ids.size*sizeof(char *));
  1110. X        } else {
  1111. X            ids.ppclogins = (char **)realloc((char *)ids.ppclogins, ids.size*sizeof(char *));
  1112. X        }
  1113. X        if ((uid_t *)0 == ids.puids || (char **)0 == ids.ppclogins) {
  1114. X            fprintf(stderr, "%s: out of memory in realloc\n", progname);
  1115. X            exit(2);
  1116. X        }
  1117. X    }
  1118. X    for (j = 0; j < ids.count; ++j) {
  1119. X        if (ids.puids[j] != pwdAdd->pw_uid) {
  1120. X            continue;
  1121. X        }
  1122. X        return 0;
  1123. X    }
  1124. X    ids.puids[j] = pwdAdd->pw_uid;
  1125. X    ids.ppclogins[j] = pcLogin;
  1126. X    ++ids.count;
  1127. X    return 0;
  1128. }
  1129. X
  1130. /*
  1131. X * this routine added the default user (the envoker) to the OLD        (ksb)
  1132. X * owners list (set up the time flags too)
  1133. X */
  1134. void
  1135. InitAll()
  1136. {
  1137. X    register char *pcUser, *pcX;
  1138. X    struct passwd *pwdUser;
  1139. X    extern char *getenv();
  1140. X    extern long time();
  1141. X
  1142. X    /* remove the XXXXX from the mktemp templates
  1143. X     */
  1144. X    pcX = acBogus + (sizeof(acBogus)-2);
  1145. X    while ('X' == *pcX)
  1146. X        *pcX-- = '\000';
  1147. X    pcX = acCopy + (sizeof(acCopy)-2);
  1148. X    while ('X' == *pcX)
  1149. X        *pcX-- = '\000';
  1150. X    iBogus = strlen(acBogus);
  1151. X    iCopy = strlen(acCopy);
  1152. X
  1153. X    FDInit(& FDLinks);
  1154. X    if (0 == getuid())
  1155. X        fSuperUser = 1;
  1156. X    (void)time(&tCutOff);
  1157. X    tCopyKeep = tCutOff - ((time_t)(60*60*24));
  1158. X    tCutOff -= ((time_t)(60*60*24))*iDays;
  1159. X
  1160. X    (void)setpwent();
  1161. X
  1162. X    bHaveRoot = 0 == geteuid();
  1163. X
  1164. #if defined(INST_FACILITY)
  1165. X    if (bHaveRoot && fExec) {
  1166. X        openlog(progname, 0, INST_FACILITY);
  1167. X    }
  1168. #endif
  1169. X    if (fSuperUser) {
  1170. X        (void)AddHer(acRoot);
  1171. X        return;
  1172. X    }
  1173. X
  1174. X    pcUser = getenv("USER");
  1175. X    if ((char *)0 == pcUser || '\000' == pcUser[0]) {
  1176. X        pcUser = getenv("LOGNAME");
  1177. X    }
  1178. X    if ((char *)0 == pcUser || '\000' == pcUser[0]) {
  1179. X        if ((struct passwd *)0 == (pwdUser = getpwuid(getuid()))) {
  1180. X            fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, getuid(), strerror(errno));
  1181. X            exit(1);
  1182. X        }
  1183. X        pcUser = pwdUser->pw_name;
  1184. X    }
  1185. X    pcUser = strcpy(malloc((strlen(pcUser)|7)+1), pcUser);
  1186. X    (void)AddHer(pcUser);
  1187. }
  1188. X
  1189. X
  1190. /*
  1191. X * show the user what we are compiled to do, as best we can        (ksb)
  1192. X */
  1193. int
  1194. Version()
  1195. {
  1196. X    register int i;
  1197. X
  1198. X    printf("%s: $Id: purge.c,v 3.1 90/11/26 12:26:41 ksb Exp $\n", progname);
  1199. X    printf("%s: default superuser login name: %s\n", progname, acRoot);
  1200. X    printf("%s: backup directory name: %s\n", progname, acOld);
  1201. X    printf("%s: valid backup directory owner", progname);
  1202. X    if (fAnyOwner) {
  1203. X        printf(": <any>");
  1204. X    } else {
  1205. X        if (ids.count > 1)
  1206. X            printf("s");
  1207. X        for (i = 0; i < ids.count; ++i)
  1208. X            printf("%c %s", i == 0 ? ':' : ',', ids.ppclogins[i]);
  1209. X    }
  1210. #if defined(INST_FACILITY)
  1211. X    printf("\n%s: syslog facility %d\n", progname, INST_FACILITY);
  1212. #else
  1213. X    printf("\n");
  1214. #endif
  1215. X    return 0;
  1216. }
  1217. X
  1218. X
  1219. /*
  1220. X * get the user-level name for this node `plain file' or `socket'    (ksb)
  1221. X *    return string, ref-out single char
  1222. X */
  1223. char *
  1224. NodeType(mType, pcChar)
  1225. unsigned int mType;
  1226. char *pcChar;
  1227. {
  1228. X    auto char acWaste[2];
  1229. X
  1230. X    if ((char *)0 == pcChar)
  1231. X        pcChar = acWaste;
  1232. X
  1233. X    switch (mType & S_IFMT) {
  1234. X    case S_IFDIR:
  1235. X        *pcChar = 'd';
  1236. X        return "directory";
  1237. #if defined(S_IFSOCK)
  1238. X    case S_IFSOCK:
  1239. X        *pcChar = 's';
  1240. X        return "socket";
  1241. #endif    /* no sockets */
  1242. #if defined(S_IFIFO)
  1243. X    case S_IFIFO:
  1244. X        *pcChar = 'p';
  1245. X        return "fifo";
  1246. #endif
  1247. #if HAVE_SLINKS
  1248. X    case S_IFLNK:
  1249. X        *pcChar = 'l';
  1250. X        return "symbolic link";
  1251. #endif
  1252. X    case S_IFBLK:
  1253. X        *pcChar = 'b';
  1254. X        return "block device";
  1255. X    case S_IFCHR:
  1256. X        *pcChar = 'c';
  1257. X        return "character device";
  1258. X    case S_IFREG:
  1259. X    case 0:
  1260. X        *pcChar = '-';
  1261. X        return "plain file";
  1262. X    default:
  1263. X        break;
  1264. X    }
  1265. X    *pcChar = '?';
  1266. X    return "type unknown";
  1267. }
  1268. X
  1269. /*
  1270. X * avoid putting . and .. in the dirs to check, we would loop        (ksb)
  1271. X */
  1272. int
  1273. DotSel(pDE)
  1274. struct direct *pDE;
  1275. {
  1276. X    register char *pcName = pDE->d_name;
  1277. X
  1278. X    return ! ('.' == pcName[0] && ('\000' == pcName[1] || '.' == pcName[1] && '\000' == pcName[2]));
  1279. }
  1280. X
  1281. /*
  1282. X * remove the file, or fake the removal                    (ksb)
  1283. X */
  1284. void
  1285. Remove(pcFile)
  1286. char *pcFile;
  1287. {
  1288. X    if (fVerbose) {
  1289. X        printf("%s: rm -f %s\n", progname, pcFile);
  1290. X    }
  1291. X    if (fExec && -1 == unlink(pcFile)) {
  1292. #if defined(INST_FACILITY)
  1293. X        if (EBUSY == errno && fExec && bHaveRoot) {
  1294. X            syslog(LOG_INFO, "still busy `%s\'", pcFile);
  1295. X        }
  1296. #endif
  1297. X        fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcFile, strerror(errno));
  1298. X        return;
  1299. X    }
  1300. #if defined(INST_FACILITY)
  1301. X    if (fExec && bHaveRoot) {
  1302. X        syslog(LOG_INFO, "rm `%s\'", pcFile);
  1303. X    }
  1304. #endif
  1305. }
  1306. X
  1307. /*
  1308. X * purge an OLD directory of outdated backup files            (ksb)
  1309. X * remove bogus links on any age
  1310. X * do not touch #inst$$ files unless ctime is > boot time?
  1311. X */
  1312. void
  1313. Purge(pcOld, pstOld)
  1314. char *pcOld;
  1315. struct stat *pstOld;
  1316. {
  1317. X    register struct direct *pDE;
  1318. X    register int i;
  1319. X    auto struct direct **ppDEDir;
  1320. X    auto char acFile[MAXPATHLEN+2], *pcLast;
  1321. X    auto int iLen;
  1322. X    auto struct stat stFile;
  1323. X
  1324. X    iLen = MAXPATHLEN - strlen(pcOld);
  1325. X    if (iLen <= 0) {
  1326. X        fprintf(stderr, "%s: Purge: %.40s... %s\n", progname, pcOld, strerror(ENAMETOOLONG));
  1327. X        return;
  1328. X    }
  1329. X    (void)strcpy(acFile, pcOld);
  1330. X    pcLast = acFile + (MAXPATHLEN - iLen);
  1331. X    if ('/' != pcLast[-1])
  1332. X        *pcLast++ = '/', --iLen;
  1333. X    if (-1 == (i = scandir(pcOld, &ppDEDir, DotSel, (int (*)())0))) {
  1334. X        fprintf(stderr, "%s: scandir: %s: %s\n", progname, pcOld, strerror(errno));
  1335. X        return;
  1336. X    }
  1337. X    for (; i > 0; free((char *)pDE)) {
  1338. X        pDE = ppDEDir[--i];
  1339. X        if (pDE->d_namlen > iLen) {
  1340. X            fprintf(stderr, "%s: Purge: ...%s/%.20s... %s\n", progname, ((20 < MAXPATHLEN - iLen) ? pcOld : pcLast-20), pDE->d_name, strerror(ENAMETOOLONG));
  1341. X            continue;
  1342. X        }
  1343. X        (void)strcpy(pcLast, pDE->d_name);
  1344. X        if (-1 == LSTAT(acFile, & stFile)) {
  1345. X            if (errno != ENOENT) {
  1346. X                fprintf(stderr, "%s: stat: %s: %s\n", progname, acFile, strerror(errno));
  1347. X            }
  1348. X            continue;
  1349. X        }
  1350. X        switch (stFile.st_mode & S_IFMT) {
  1351. X        default:
  1352. X            fprintf(stderr, "%s: %s: is a %s?\n", progname, acFile, NodeType(stFile.st_mode, (char *)0));
  1353. X            continue;
  1354. #if HAVE_SLINKS
  1355. X        case S_IFLNK:
  1356. #endif
  1357. X        case S_IFREG:
  1358. X        case 0:
  1359. X            break;
  1360. X        }
  1361. X        /* if the file is a bogus link to a running program,
  1362. X         * try to remove it always...
  1363. X         */
  1364. X        if (0 == strncmp(pcLast, acBogus, iBogus)) {
  1365. X            Remove(acFile);
  1366. X            continue;
  1367. X        }
  1368. X
  1369. X        /* if the file is a temp file used by install ignore it
  1370. X         * for at least 1 day, then remove it
  1371. X         */
  1372. X        if (0 == strncmp(pcLast, acCopy, iCopy)) {
  1373. X            if (tCopyKeep <= stFile.st_ctime) {
  1374. X                continue;
  1375. X            }
  1376. X        } else if (tCutOff <= stFile.st_ctime) {
  1377. X            continue;
  1378. X        }
  1379. X
  1380. X        /* sticky problem -- we should not remove the evidence of a
  1381. X         * poor install (the product might still be installed in a
  1382. X         * binary directory) so we need to keep this node here...
  1383. X         * but if we find it again we can remove it, see?
  1384. X         */
  1385. X        if (stFile.st_nlink > 1) {
  1386. X            register char *pcLink;
  1387. X
  1388. X            pcLink = FDAdd(&FDLinks, acFile, &stFile);
  1389. X            if (0 == strcmp(acFile, pcLink)) {
  1390. X                continue;
  1391. X            }
  1392. X        }
  1393. X        Remove(acFile);
  1394. X    }
  1395. X    free((char *)ppDEDir);
  1396. }
  1397. X
  1398. /*
  1399. X * scan under a directory of all the OLD dirs and purge them        (ksb)
  1400. X */
  1401. void
  1402. Scan(pcDir)
  1403. char *pcDir;
  1404. {
  1405. X    register struct direct *pDE;
  1406. X    register int i;
  1407. X    auto struct direct **ppDEDir;
  1408. X    auto char acDown[MAXPATHLEN+2], *pcLast;
  1409. X    auto struct stat stDown;
  1410. X    auto int iLen;
  1411. X
  1412. X    if ((char *)0 == pcDir || '\000' == *pcDir)
  1413. X        pcDir = ".";
  1414. X    iLen = MAXPATHLEN - strlen(pcDir);
  1415. X    if (iLen <= 0) {
  1416. X        fprintf(stderr, "%s: Scan: %.40s... %s\n", progname, pcDir, strerror(ENAMETOOLONG));
  1417. X        return;
  1418. X    }
  1419. X    (void)strcpy(acDown, pcDir);
  1420. X    pcLast = acDown + (MAXPATHLEN - iLen);
  1421. X    if ('/' != pcLast[-1])
  1422. X        *pcLast++ = '/', --iLen;
  1423. X    if (-1 == (i = scandir(pcDir, &ppDEDir, DotSel, (int (*)())0))) {
  1424. X        fprintf(stderr, "%s: scandir: %s: %s\n", progname, pcDir, strerror(errno));
  1425. X        return;
  1426. X    }
  1427. X    for (; i > 0; free((char *)pDE)) {
  1428. X        pDE = ppDEDir[--i];
  1429. X        if (pDE->d_namlen > iLen) {
  1430. X            fprintf(stderr, "%s: Scan: ...%s/%.20s... %s\n", progname, ((20 < MAXPATHLEN - iLen) ? pcDir : pcLast-20), pDE->d_name, strerror(ENAMETOOLONG));
  1431. X            continue;
  1432. X        }
  1433. X        (void)strcpy(pcLast, pDE->d_name);
  1434. X        if (-1 == LSTAT(acDown, & stDown)) {
  1435. X            if (errno != ENOENT) {
  1436. X                fprintf(stderr, "%s: stat: %s: %s\n", progname, acDown, strerror(errno));
  1437. X            }
  1438. X            continue;
  1439. X        }
  1440. X        if (0 == strcmp(acOld, pDE->d_name)) {
  1441. X            if (isSysId((uid_t)stDown.st_uid)) {
  1442. X                Purge(acDown, & stDown);
  1443. X            }
  1444. X            continue;
  1445. X        }
  1446. X        /* if this directory an nfs (NFS) mount point?
  1447. X         * We used to use:
  1448. X         *    (255 == major(stDown.st_dev))
  1449. X         */
  1450. X        if (0 != (0x80 & major(stDown.st_dev))) {
  1451. X            continue;
  1452. X        }
  1453. X        if (S_IFDIR == (stDown.st_mode & S_IFMT)) {
  1454. X            Scan(acDown);
  1455. X        }
  1456. X    }
  1457. X    free((char *)ppDEDir);
  1458. }
  1459. X
  1460. /*
  1461. X * let purge read paths to purge from find(1) output            (ksb)
  1462. X */
  1463. static void
  1464. DoStdin()
  1465. {
  1466. X    static int fBeenHere = 0;
  1467. X    register char *pcNl;
  1468. X    auto char acIn[MAXPATHLEN+2];
  1469. X    auto int c;
  1470. X
  1471. X    if (fBeenHere++) {
  1472. X        fprintf(stderr, "%s: will not recurse on stdin (skipped)\n", progname);
  1473. X        return;
  1474. X    }
  1475. X    while ((char *)0 != fgets(acIn, MAXPATHLEN+1, stdin)) {
  1476. X        if ((char *)0 == (pcNl = strchr(acIn, '\n'))) {
  1477. X            fprintf(stderr, "%s: line too long on stdin\n", progname);
  1478. X            while (EOF != (c = getc(stdin))) {
  1479. X                if ('\n' == c)
  1480. X                    break;
  1481. X            }
  1482. X            continue;
  1483. X        }
  1484. X        *pcNl = '\000';
  1485. X        Which(acIn);
  1486. X    }
  1487. X    clearerr(stdin);
  1488. X    --fBeenHere;
  1489. }
  1490. X
  1491. /*
  1492. X * the user may have either given us /bin or /bin/OLD to purge.        (ksb)
  1493. X * choose the correct routine and purge it.
  1494. X *
  1495. X * if an old script gives us a number of days do / with that number (yucko).
  1496. X */
  1497. void
  1498. Which(pcDir)
  1499. char *pcDir;
  1500. {
  1501. X    register char *pcSlash;
  1502. X    auto struct stat stDir;
  1503. X
  1504. X    if (AllDigits(pcDir) && -1 == access(pcDir, 0)) {
  1505. X        fprintf(stderr, "%s: warning: old style [ndays] option\n", progname);
  1506. X        iDays = atoi(pcDir);
  1507. X        pcDir = "/";
  1508. X    }
  1509. X    if ('-' == pcDir[0] && '\000' == pcDir[1]) {
  1510. X        DoStdin();
  1511. X        return;
  1512. X    }
  1513. X    if ((char *)0 == (pcSlash = strrchr(pcDir, '/'))) {
  1514. X        pcSlash = pcDir;
  1515. X    } else {
  1516. X        ++pcSlash;
  1517. X    }
  1518. X    if (0 == strcmp(acOld, pcSlash)) {
  1519. X        if (-1 == LSTAT(pcDir, & stDir)) {
  1520. X            fprintf(stderr, "%s: stat: %s: %s\n", progname, pcDir, strerror(errno));
  1521. X        } else if (!isSysId((uid_t)stDir.st_uid)) {
  1522. X            fprintf(stderr, "%s: %s: %d: not a user to purge\n", progname, pcDir, stDir.st_uid);
  1523. X        } else {
  1524. X            Purge(pcDir, &stDir);
  1525. X        }
  1526. X    } else {
  1527. X        Scan(pcDir);
  1528. X    }
  1529. }
  1530. X
  1531. /*
  1532. X * this checks to see if we recovered from the errors we found        (ksb)
  1533. X */
  1534. static int
  1535. StillBad(pAE)
  1536. AE_ELEMENT *pAE;
  1537. {
  1538. X    auto struct stat stThis;
  1539. X    register char *pcSlash;
  1540. X
  1541. X    if (-1 != LSTAT(pAE->pcname, &stThis) && stThis.st_nlink > 1) {
  1542. X        if ((char *)0 != (pcSlash = strrchr(pAE->pcname, '/'))) {
  1543. X            *pcSlash = '\000';
  1544. X            fprintf(stderr, "%s: %s/%s: link count %d, use `instck -i %s\' to repair\n", progname, pAE->pcname, pcSlash+1, stThis.st_nlink, pAE->pcname);
  1545. X            *pcSlash = '/';
  1546. X        } else {
  1547. X            fprintf(stderr, "%s: %s: has a link count > 1, use instck to repair\n", progname, pAE->pcname);
  1548. X        }
  1549. X    } else {
  1550. X        Remove(pAE->pcname);
  1551. X    }
  1552. X    return 0;
  1553. }
  1554. X
  1555. /*
  1556. X * When done scan any file that have bad link counts and see if we     (ksB)
  1557. X * removed the other links via purging OLD dirs
  1558. X */
  1559. void
  1560. Done()
  1561. {
  1562. X    (void)FDScan(FDLinks, StillBad);
  1563. X
  1564. #if defined(INST_FACILITY)
  1565. X    if (bHaveRoot && fExec) {
  1566. X        closelog();
  1567. X    }
  1568. #endif
  1569. }
  1570. Purdue
  1571. chmod 0444 purge/purge.c ||
  1572. echo 'restore of purge/purge.c failed'
  1573. Wc_c="`wc -c < 'purge/purge.c'`"
  1574. test 14969 -eq "$Wc_c" ||
  1575.     echo 'purge/purge.c: original size 14969, current size' "$Wc_c"
  1576. fi
  1577. # ============= install.d/special.i ==============
  1578. if test -f 'install.d/special.i' -a X"$1" != X"-c"; then
  1579.     echo 'x - skipping install.d/special.i (File already exists)'
  1580. else
  1581. echo 'x - extracting install.d/special.i (Text)'
  1582. sed 's/^X//' << 'Purdue' > 'install.d/special.i' &&
  1583. /*
  1584. X * $Id: special.i,v 7.2 90/10/22 11:47:15 ksb Exp $
  1585. X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
  1586. X * 47907.  All rights reserved.
  1587. X *
  1588. X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
  1589. X *
  1590. X * This software is not subject to any license of the American Telephone
  1591. X * and Telegraph Company or the Regents of the University of California.
  1592. X *
  1593. X * Permission is granted to anyone to use this software for any purpose on
  1594. X * any computer system, and to alter it and redistribute it freely, subject
  1595. X * to the following restrictions:
  1596. X *
  1597. X * 1. Neither the authors nor Purdue University are responsible for any
  1598. X *    consequences of the use of this software.
  1599. X *
  1600. X * 2. The origin of this software must not be misrepresented, either by
  1601. X *    explicit claim or by omission.  Credit to the authors and Purdue
  1602. X *    University must appear in documentation and sources.
  1603. X *
  1604. X * 3. Altered versions must be plainly marked as such, and must not be
  1605. X *    misrepresented as being the original software.
  1606. X *
  1607. X * 4. This notice may not be removed or altered.
  1608. X */
  1609. X
  1610. /*
  1611. X * this (long) C routine is expanded twice in instck, and only once
  1612. X * in install.  It is the one that searchs a config file.
  1613. X */
  1614. X
  1615. #if defined(INSTCK)
  1616. /*
  1617. X * Scan the gien dirs for pats in the check file list?          (ksb)
  1618. X * config file format:
  1619. X *    #file    mode        owner    group    strip    message
  1620. X *    /unix    -r??r--r--    root    *    n
  1621. X * `*' = any
  1622. X * `"' = last
  1623. X * `=' = the default for this col
  1624. X * `!' = not (!mode -> not exist, !group/!owner -> any but the one listed)
  1625. X */
  1626. void
  1627. DirCk(iCount, ppcDirs, pcConfig, pCL)
  1628. int iCount;        /* who many dirs to search            */
  1629. char **ppcDirs;        /* dirs to search                */
  1630. #else /* install */
  1631. void
  1632. /*
  1633. X * Is the named file in the check file list?  If so is it OK?        (ksb)
  1634. X *    FAIL is file it in list and modes are bad
  1635. X *    else SUCCESS
  1636. X * config file format:
  1637. X *    #file    mode        owner    group    strip    message
  1638. X *    /unix    -r??r--r--    root    *    n
  1639. X *    core    !r?-?--?--    *    *    n
  1640. X * `*' = any
  1641. X * `"' = last
  1642. X * `=' = the default for this col
  1643. X * `!' = not (!mode -> not exist, !group/!owner -> any but the one listed)
  1644. X */
  1645. Special(pcFile, pcConfig, pCL)
  1646. char *pcFile;        /* file we are searching for            */
  1647. #endif
  1648. char *pcConfig;        /* check list file name to read            */
  1649. CHLIST *pCL;        /* pointer to the check list to build/use    */
  1650. {
  1651. X    extern char *malloc();
  1652. X    static FILE *fpCnf = (FILE *)0;
  1653. X    static char *pcCnf = "jms & ksb";
  1654. X    static char acLine[MAXCNFLINE];
  1655. X    static char acMesg[MAXCNFLINE];
  1656. X    static char acEq[] = "=", acAny[] = "*";
  1657. X    register char *pcSkip, *pcBlank;
  1658. X    register int iLine;
  1659. #if defined(INSTCK)
  1660. X    register int i;
  1661. X    auto char *pcCurGlob;
  1662. #else
  1663. X    auto char *pcLastComp;
  1664. X    auto char acFPath[MAXPATHLEN+1];
  1665. #endif
  1666. X
  1667. X    pCL->ffound = FALSE;
  1668. X
  1669. X    if ((char *)0 == pcConfig || '\000' == pcConfig[0]) {
  1670. #if defined(INSTCK)
  1671. X        (void)printf("%s: no configuration file\n", progname);
  1672. #endif
  1673. X        return;
  1674. X    }
  1675. X    if (NULL == fpCnf || pcCnf != pcConfig) {
  1676. X        if (NULL != fpCnf)
  1677. X            (void)fclose(fpCnf);
  1678. X        pcCnf = pcConfig;
  1679. X        if (NULL == (fpCnf = fopen(pcCnf, "r"))) {
  1680. X            (void)fprintf(stderr, "%s: fopen (checklist): %s: %s\n", progname, pcCnf, strerror(errno));
  1681. X            exit(EXIT_OPT);
  1682. X        }
  1683. #if defined(F_SETFD)
  1684. X        /* if we can we set the close-on-exec bit to be neat */
  1685. X        (void)fcntl(fileno(fpCnf), F_SETFD, 1);
  1686. #endif    /* have close on exec bit to twidle    */
  1687. X    } else {
  1688. X        (void)rewind(fpCnf);
  1689. X    }
  1690. X    pCL->pcspecial = pcCnf;
  1691. X
  1692. #if defined(INSTALL)
  1693. X    if ('/' != pcFile[0]) {
  1694. X        (void)getwd(acFPath);
  1695. X        (void)strcat(acFPath, "/");
  1696. X        (void)strcat(acFPath, pcFile);
  1697. X        pcFile = CompPath(acFPath);
  1698. X    } else {
  1699. X        (void)strcpy(acFPath, pcFile);    /* don't munge argument! */
  1700. X        pcFile = CompPath(acFPath);
  1701. X    }
  1702. X
  1703. X    if ((char *)0 == (pcLastComp = strrchr(pcFile, '/'))) {
  1704. X        Die("nil pointer");
  1705. X    }
  1706. X    ++pcLastComp;
  1707. #endif
  1708. X
  1709. X    /* we set the defaults:
  1710. X     * not found, plain file, mode, owner, group, no strip
  1711. X     */
  1712. X    iLine = 0;
  1713. X    (void)strcpy(acLine, "* = = = =\n");
  1714. X    (void)strcpy(acMesg, "default message");
  1715. X    pCL->pcmesg = acMesg;
  1716. X    pCL->pclink = (char *)0;
  1717. X    pCL->acmode[0] = pCL->acmode[1] = '\000';
  1718. X
  1719. X    do {
  1720. X        if ((char *)0 == (pcBlank = strchr(acLine, '\n'))) {
  1721. X            (void)fprintf(stderr, "%s: %s(%d) line too long\n", progname, pcCnf, iLine);
  1722. X            exit(EXIT_OPT);
  1723. X        }
  1724. X        do {
  1725. X            *pcBlank = '\000';
  1726. X        } while (pcBlank != acLine && (--pcBlank, isspace(*pcBlank)));
  1727. X        for (pcSkip = acLine; isspace(*pcSkip); ++pcSkip)
  1728. X            /*empty*/;
  1729. X        if ('\000' == pcSkip[0] || '#' == pcSkip[0])
  1730. X            continue;
  1731. X
  1732. X        for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
  1733. X            /*empty*/;
  1734. X        while (isspace(*pcBlank))
  1735. X            *pcBlank++ = '\000';
  1736. X        pCL->iline = iLine;
  1737. X        pCL->pcpat = pcSkip;
  1738. #if defined(INSTCK)
  1739. X        pcCurGlob = pcSkip;
  1740. #else
  1741. X        if (0 != iLine) {
  1742. X            pCL->ffound = SamePath(pcSkip, RJust(pcSkip, pcFile, pcLastComp));
  1743. X        }
  1744. #endif
  1745. X
  1746. X        /* mode or link */
  1747. X        pcSkip = pcBlank;
  1748. X        for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
  1749. X            /*empty*/;
  1750. X        while (isspace(*pcBlank))
  1751. X            *pcBlank++ = '\000';
  1752. X
  1753. X        /* file is a link */
  1754. X        if ('@' == pcSkip[0] || ':' == pcSkip[0]) {
  1755. X            pCL->pclink = strcpy(malloc(strlen(pcSkip)+1),pcSkip);
  1756. X            goto at_comment;
  1757. X        } else if ((char *)0 != pCL->pclink) {
  1758. X            free(pCL->pclink);
  1759. X            pCL->pclink = (char *)0;
  1760. X        }
  1761. X        if ('~' == pcSkip[0] || '!' == pcSkip[0] || '*' == pcSkip[0]) {
  1762. X            (void)strcpy(pCL->acmode, pcSkip);
  1763. X            if ('\000' != pcSkip[1]) {
  1764. X                CvtMode(pcSkip+1, &pCL->mmust, &pCL->moptional);
  1765. X                pCL->mtype = pCL->mmust & S_IFMT;
  1766. X                pCL->mmust &= 07777;
  1767. X            } else {
  1768. X                pCL->mtype = 0;
  1769. X                pCL->mmust = 0;
  1770. X                pCL->moptional = 0644;
  1771. X            }
  1772. X        } else if (EQUAL(pcSkip, acEq)) {
  1773. X            if ((char *)0 == DEFMODE) {
  1774. X                pCL->acmode[0] = '*';
  1775. X            } else {
  1776. X                CvtMode(DEFMODE, &pCL->mmust, &pCL->moptional);
  1777. X                pCL->acmode[0] = '\000';
  1778. X            }
  1779. X        } else if ('\"' == pcSkip[0] && '\000' == pcSkip[1]) {
  1780. X            /* use previous */;
  1781. X        } else {
  1782. X            CvtMode(pcSkip, &pCL->mmust, &pCL->moptional);
  1783. X            pCL->moptional &= 07777;
  1784. X            pCL->acmode[0] = '\000';
  1785. X        }
  1786. X        if ('\000' == pCL->acmode[0]) {
  1787. X            pCL->mtype = pCL->mmust & S_IFMT;
  1788. X            pCL->mmust &= 07777;
  1789. X            (void)NodeType(pCL->mtype, pCL->acmode);
  1790. X        }
  1791. X        if (0 == pCL->mtype) {
  1792. X            pCL->mtype = S_IFREG;
  1793. X        }
  1794. X
  1795. X        /* owner */
  1796. X        pcSkip = pcBlank;
  1797. X        for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
  1798. X            /*empty*/;
  1799. X        while (isspace(*pcBlank))
  1800. X            *pcBlank++ = '\000';
  1801. X        pCL->fbangowner = 0;
  1802. X        if ('!' == *pcSkip) {
  1803. X            pCL->fbangowner = 1;
  1804. X            ++pcSkip;
  1805. X        }
  1806. X        if (EQUAL(pcSkip, acEq)) {
  1807. X            if ((struct passwd *)0 != pwdDef) {
  1808. X                (void)strcpy(pCL->acowner, pwdDef->pw_name);
  1809. X            } else if ((char *)0 == DEFOWNER) {
  1810. X                (void)strcpy(pCL->acowner, acAny);
  1811. X            } else {
  1812. X                (void)strcpy(pCL->acowner, DEFOWNER);
  1813. X            }
  1814. X        } else if (! EQUAL(pcSkip, "\"")) {
  1815. X            (void)strcpy(pCL->acowner, pcSkip);
  1816. X        }
  1817. X
  1818. X        /* group */
  1819. X        pcSkip = pcBlank;
  1820. X        for (pcBlank = pcSkip; ! isspace(*pcBlank); ++pcBlank)
  1821. X            /*empty*/;
  1822. X        while (isspace(*pcBlank))
  1823. X            *pcBlank++ = '\000';
  1824. X        pCL->fbanggroup = 0;
  1825. X        if ('!' == *pcSkip) {
  1826. X            pCL->fbanggroup = 1;
  1827. X            ++pcSkip;
  1828. X        }
  1829. X        if (EQUAL(pcSkip, acEq)) {
  1830. X            if ((struct group *)0 != grpDef) {
  1831. X                (void)strcpy(pCL->acgroup, grpDef->gr_name);
  1832. X            } else if ((char *)0 == DEFGROUP) {
  1833. X                (void)strcpy(pCL->acgroup, acAny);
  1834. X            } else {
  1835. X                (void)strcpy(pCL->acgroup, DEFGROUP);
  1836. X            }
  1837. X        } else if (! EQUAL(pcSkip, "\"")) {
  1838. X            (void)strcpy(pCL->acgroup, pcSkip);
  1839. X        }
  1840. X
  1841. X        /* strip or not */
  1842. X        pcSkip = pcBlank;
  1843. X        for (pcBlank = pcSkip; '\000' != *pcBlank && ! isspace(*pcBlank); ++pcBlank)
  1844. X            /*empty*/;
  1845. X        while (isspace(*pcBlank))
  1846. X            *pcBlank++ = '\000';
  1847. X        if (EQUAL(pcSkip, acEq)) {
  1848. X            pCL->chstrip = CF_NONE;
  1849. X        } else switch (*pcSkip) {
  1850. X        case 's':        /* yeah we should take these too */
  1851. X        case 'S':
  1852. X            pCL->chstrip = CF_STRIP;
  1853. X            break;
  1854. X        case 'l':
  1855. X        case 'L':
  1856. X            pCL->chstrip = CF_RANLIB;
  1857. X            break;
  1858. X        default:
  1859. X            (void)fprintf(stderr, "%s: unknown strip indicator `%s\'\n", progname, pcSkip);
  1860. X            /* fall through to recover */
  1861. X        case '-':
  1862. X        case 'n':
  1863. X        case 'N':
  1864. X            pCL->chstrip = CF_NONE;
  1865. X            break;
  1866. X        case '*':
  1867. X        case '\?':
  1868. X            pCL->chstrip = CF_ANY;
  1869. X            break;
  1870. X        case '\"':
  1871. X            break;
  1872. X        }
  1873. X
  1874. X    at_comment:
  1875. X        if (! EQUAL(pcBlank, "\"")) {
  1876. X            (void)strcpy(acMesg, pcBlank);
  1877. X        }
  1878. X
  1879. X        if (0 == iLine)
  1880. X            continue;
  1881. X
  1882. #if defined(INSTALL)
  1883. X        if (!pCL->ffound) {
  1884. X            continue;
  1885. X        }
  1886. #endif
  1887. X
  1888. X        if ('*' != pCL->acowner[0] || '\000' != pCL->acowner[1]) {
  1889. X            struct passwd *pwd;
  1890. X            if ((struct passwd *)0 != pwdDef && 0 == strcmp(pCL->acowner, pwdDef->pw_name)) {
  1891. X                pCL->uid = pwdDef->pw_uid;
  1892. X            } else if ((struct passwd *)0 == (pwd = getpwnam(pCL->acowner))) {
  1893. X                fprintf(stderr, "%s: getpwname: %s: no such user\n", progname, pCL->acowner);
  1894. X                continue;
  1895. X            } else {
  1896. X                pCL->uid = pwd->pw_uid;
  1897. X            }
  1898. X        } else if (0 != (S_ISUID & pCL->mmust)) {
  1899. X            BadSet(iLine, 'u', "user", pCL->acmode);
  1900. X        }
  1901. X        if ('*' != pCL->acgroup[0] || '\000' != pCL->acgroup[1]) {
  1902. X            struct group *grp;
  1903. X            if ((struct group *)0 != grpDef && 0 == strcmp(pCL->acgroup, grpDef->gr_name)) {
  1904. X                pCL->gid = grpDef->gr_gid;
  1905. X            } else if ((struct group *)0 == (grp = getgrnam(pCL->acgroup))) {
  1906. X                fprintf(stderr, "%s: getgrname: %s: no such group\n", progname, pCL->acgroup);
  1907. X                continue;
  1908. X            } else {
  1909. X                pCL->gid = grp->gr_gid;
  1910. X            }
  1911. X        } else if (0 != (S_ISGID & pCL->mmust)) {
  1912. X            BadSet(iLine, 'g', "group", pCL->acmode);
  1913. X        }
  1914. X
  1915. X        ModetoStr(pCL->acmode+1, pCL->mmust, pCL->moptional);
  1916. #if defined(INSTCK)
  1917. X        iMatches = 0;
  1918. X        if ('/' == *pcCurGlob) {
  1919. X            FileMatch(pcCurGlob+1, "/", DoCk);
  1920. X            if (0 == iMatches) {
  1921. X                NoMatches(pcCurGlob);
  1922. X            }
  1923. X        } else {
  1924. X            /* never a no-matches check here, might not have
  1925. X             * any command line dirs to search, etc [ksb]
  1926. X             */
  1927. X            for (i = 0; i < iCount; ++i) {
  1928. X                FileMatch(pcCurGlob, ppcDirs[i], DoCk);
  1929. X            }
  1930. X        }
  1931. #else
  1932. X        if (FALSE != fVerbose || FALSE != fTrace) {
  1933. X            (void)printf("%s: found `%s\' in %s\n", progname, pcFile, pcConfig);
  1934. X        }
  1935. X        break;
  1936. #endif
  1937. X    } while (++iLine, NULL != fgets(acLine, MAXCNFLINE, fpCnf));
  1938. }
  1939. Purdue
  1940. chmod 0444 install.d/special.i ||
  1941. echo 'restore of install.d/special.i failed'
  1942. Wc_c="`wc -c < 'install.d/special.i'`"
  1943. test 9712 -eq "$Wc_c" ||
  1944.     echo 'install.d/special.i: original size 9712, current size' "$Wc_c"
  1945. fi
  1946. # ============= purge/Makefile ==============
  1947. if test -f 'purge/Makefile' -a X"$1" != X"-c"; then
  1948.     echo 'x - skipping purge/Makefile (File already exists)'
  1949. else
  1950. echo 'x - extracting purge/Makefile (Text)'
  1951. sed 's/^X//' << 'Purdue' > 'purge/Makefile' &&
  1952. #    $Id: Makefile.plain,v 7.2 90/11/28 08:52:39 ksb Exp $
  1953. #
  1954. #    Makefile for purge
  1955. #
  1956. X
  1957. PROG=    purge
  1958. BIN=    ${DESTDIR}/usr/local/etc
  1959. MANROOT= ${DESTDIR}/usr/man
  1960. X
  1961. # where is the source code for install(1L)?
  1962. INSTALLD= ../install.d
  1963. #INSTALLD= /usr/src/usr.bin/install.d
  1964. #INSTALLD= /usr/src/local/cmd/install.d
  1965. X
  1966. # which type of links to build
  1967. #LN=ln
  1968. LN=ln -s
  1969. X
  1970. L=../libopt
  1971. #L=/usr/include/local
  1972. I=/usr/include
  1973. S=/usr/include/sys
  1974. P=
  1975. X
  1976. INCLUDE= -I$L
  1977. DEBUG=    -O
  1978. CDEFS=  
  1979. CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
  1980. X
  1981. LINKH=    configure.h install.h
  1982. LINKC=    
  1983. LINK=    ${LINKH} ${LINKC}
  1984. GENH=    ${LINKH}
  1985. GENC=    ${LINKC}
  1986. GEN=    ${GENC} ${GENH}
  1987. HDR=    main.h purge.h filedup.h
  1988. SRC=    main.c purge.c filedup.c
  1989. DEP=    ${GENC} ${SRC}
  1990. OBJ=    main.o purge.o filedup.o
  1991. MAN=    purge.8l
  1992. OTHER=    README purge.m
  1993. SOURCE=    Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
  1994. X
  1995. all: ${PROG}
  1996. X
  1997. ${PROG}:$P ${OBJ}
  1998. #    ${CC} -o $@ ${CFLAGS} ${OBJ} -lopt
  1999. #    ${CC} -o $@ ${CFLAGS} ${OBJ} -L /usr/local/lib -lopt
  2000. X    ${CC} -o $@ ${CFLAGS} ${OBJ} ../libopt/libopt.a
  2001. X
  2002. #main.h: main.c
  2003. #
  2004. #main.c: ${PROG}.m
  2005. #    mkcmd std_help.m ${PROG}.m
  2006. #    -(cmp -s prog.c main.c || (cp prog.c main.c && echo main.c updated))
  2007. #    -(cmp -s prog.h main.h || (cp prog.h main.h && echo main.h updated))
  2008. #    rm -f prog.[ch]
  2009. X
  2010. swap: ${PROG}.m
  2011. X    mv Makefile Makefile.plain
  2012. X    mv Makefile.mkcmd Makefile
  2013. X    mkcmd std_help.m ${PROG}.m
  2014. X    -cmp -s prog.c main.c || echo main.c changed
  2015. X    -cmp -s prog.h main.h || echo main.h changed
  2016. X    rm -f prog.[ch]
  2017. X    make depend
  2018. X
  2019. links: ${LINK}
  2020. X
  2021. ${LINK}:
  2022. X    ${LN} ${INSTALLD}/$@ ./$@
  2023. X
  2024. clean: FRC
  2025. X    rm -f Makefile.bak ${PROG} ${GEN} *.o a.out core errs lint.out tags
  2026. X
  2027. calls: ${SRC} ${HDR} ${GEN} FRC
  2028. X    calls ${CDEFS} ${INCLUDE} ${DEP}
  2029. X
  2030. depend: ${SRC} ${HDR} ${GEN} FRC
  2031. X    maketd ${CDEFS} ${INCLUDE} ${DEP}
  2032. X
  2033. dirs: ${BIN}
  2034. X
  2035. install: all dirs FRC
  2036. X    install -cs ${PROG} ${BIN}/${PROG}
  2037. X
  2038. lint: ${SRC} ${HDR} ${GEN} FRC
  2039. X    lint -h ${CDEFS} ${INCLUDE} ${DEP}
  2040. X
  2041. mkcat: ${MAN}
  2042. X    mkcat -r${MANROOT} ${MAN}
  2043. X
  2044. print: source FRC
  2045. X    lpr -J'${PROG} source' ${SOURCE}
  2046. X
  2047. source: ${SOURCE}
  2048. X
  2049. spotless: clean
  2050. X    rcsclean ${SOURCE}
  2051. X
  2052. tags: ${HDR} ${SRC} ${GEN}
  2053. X    ctags -t ${HDR} ${SRC} ${GEN}
  2054. X
  2055. / ${BIN}:
  2056. X    install -dr $@
  2057. X
  2058. ${SOURCE}:
  2059. X    co -q $@
  2060. X
  2061. FRC:
  2062. X
  2063. # DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
  2064. X
  2065. main.o: $L/getopt.h configure.h install.h main.c purge.h
  2066. X
  2067. purge.o: configure.h filedup.h install.h main.h purge.c purge.h
  2068. X
  2069. filedup.o: filedup.c filedup.h
  2070. X
  2071. # *** Do not add anything here - It will go away. ***
  2072. Purdue
  2073. chmod 0644 purge/Makefile ||
  2074. echo 'restore of purge/Makefile failed'
  2075. Wc_c="`wc -c < 'purge/Makefile'`"
  2076. test 2355 -eq "$Wc_c" ||
  2077.     echo 'purge/Makefile: original size 2355, current size' "$Wc_c"
  2078. fi
  2079. # ============= install.d/TODO ==============
  2080. if test -f 'install.d/TODO' -a X"$1" != X"-c"; then
  2081.     echo 'x - skipping install.d/TODO (File already exists)'
  2082. else
  2083. echo 'x - extracting install.d/TODO (Text)'
  2084. sed 's/^X//' << 'Purdue' > 'install.d/TODO' &&
  2085. # $Id: TODO,v 7.0 90/09/17 09:41:37 ksb Exp $
  2086. X
  2087. Last thing install should do:
  2088. X
  2089. in the configuration file one should be able to note that a file
  2090. should be owned (grouped/moded) to the same owner (group/mode) as
  2091. another file in the file system:
  2092. X
  2093. /bin/df        -rwxr-s?-x    root    :/dev/rf0a    s    reads disk
  2094. X
  2095. let the colon indicate that it is a file to stat to get the
  2096. group from....
  2097. X
  2098. kayessbee
  2099. Purdue
  2100. chmod 0444 install.d/TODO ||
  2101. echo 'restore of install.d/TODO failed'
  2102. Wc_c="`wc -c < 'install.d/TODO'`"
  2103. test 379 -eq "$Wc_c" ||
  2104.     echo 'install.d/TODO: original size 379, current size' "$Wc_c"
  2105. fi
  2106. # ============= install.d/myself.cf ==============
  2107. if test -f 'install.d/myself.cf' -a X"$1" != X"-c"; then
  2108.     echo 'x - skipping install.d/myself.cf (File already exists)'
  2109. else
  2110. echo 'x - extracting install.d/myself.cf (Text)'
  2111. sed 's/^X//' << 'Purdue' > 'install.d/myself.cf' &&
  2112. # this configuration file is used *just* to install install, itself    (ksb)
  2113. # $Id: myself.cf,v 7.0 90/10/08 11:39:55 ksb Exp $
  2114. X
  2115. /usr/bin/install         -rwxr-xr-x      root    *    ?
  2116. OLD                      drwxr-xr-x      root    *    -
  2117. Purdue
  2118. chmod 0444 install.d/myself.cf ||
  2119. echo 'restore of install.d/myself.cf failed'
  2120. Wc_c="`wc -c < 'install.d/myself.cf'`"
  2121. test 232 -eq "$Wc_c" ||
  2122.     echo 'install.d/myself.cf: original size 232, current size' "$Wc_c"
  2123. fi
  2124. true || echo 'restore of install.d/special.c failed'
  2125. echo End of part 4, continue with part 5
  2126. exit 0
  2127.  
  2128. exit 0 # Just in case...
  2129.