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

  1. Subject:  v24i063:  Purdue software product installation system, Part01/07
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: d9e84b49 f7d28c89 a7386cf0 804cacaa
  5.  
  6. Submitted-by: Kevin Braunsdorf <ksb@nostromo.cc.purdue.edu>
  7. Posting-number: Volume 24, Issue 63
  8. Archive-name: pucc-install/part01
  9.  
  10. Submitted-by: ksb@cc.purdue.edu (Kevin Braunsdorf)
  11. Archive-name: pucc-1b/part01
  12.  
  13. This seven part archive contains the basic `product installation'
  14. system that we use a PUCC.  You'll need the first part (libs + maketd)
  15. to compile these.
  16.     install(1l)    - update a file or directory with a guaranteed backup
  17.     instck(1l)    - look for improperly installed files
  18.     purge(8l)    - remove outdated backup copies of installed programs
  19. Install is a tool for updating system files in a controlled environment.
  20. The design philosophy of install is to automate the installation process
  21. and put it as much out of reach of human carelessness as possible, while
  22. providing a flexible, easy to use tool.
  23.  
  24. Among its features,Install provides the following install increases system
  25. security by providing a controlled installation environment.  It checks
  26. the actions of the superuser against a configuration file that you build
  27. (either by hand or using instck), and can prevent grievous mistakes such
  28. as installing a shell setuid to a privileged user, or installing a
  29. world\(hywritable password file.  An appropriate configuration file can
  30. guarantee that files are installed with correct owner, group and mode,
  31. that strip is run on binaries and ranlib is run on libraries.
  32.  
  33. Regardless of whether you create a configuration file, install warns you
  34. of many possible errors, unless you make it quiet with its \-q option.
  35. For instance, if you install a new version of the ex(1) editor and forget
  36. to update its links, install will notice the extra links to the existing
  37. version and warn you that you might be making a mistake.
  38.  
  39.  
  40. #!/bin/sh
  41. # This is pucc-1b, a shell archive (produced by shar 3.49)
  42. # To extract the files from this archive, save it to a file, remove
  43. # everything above the "!/bin/sh" line above, and type "sh file_name".
  44. #
  45. # made 11/29/1990 17:23 UTC by ksb@cc.purdue.edu (Kevin Braunsdorf)
  46. # Source directory /ksb/c.s.u-2
  47. #
  48. # existing files will NOT be overwritten unless -c is specified
  49. #
  50. # This shar contains:
  51. # length  mode       name
  52. # ------ ---------- ------------------------------------------
  53. #   1813 -rw-r--r-- INSTALL.02
  54. #  34702 -r--r--r-- instck/instck.c
  55. #  13940 -r--r--r-- instck/gen.c
  56. #    322 -r--r--r-- purge/README
  57. #  46361 -r--r--r-- install.d/file.c
  58. #   2505 -r--r--r-- instck/instck.h
  59. #  19085 -r--r--r-- install.d/main.c
  60. #  18260 -r--r--r-- install.d/syscalls.c
  61. #   8078 -r--r--r-- instck/main.c
  62. #   1858 -r--r--r-- instck/main.h
  63. #   1669 -r--r--r-- install.cf/install.cf
  64. #  21337 -r--r--r-- install.d/install.1l
  65. #  14969 -r--r--r-- purge/purge.c
  66. #   9712 -r--r--r-- install.d/special.i
  67. #   2355 -rw-r--r-- purge/Makefile
  68. #    379 -r--r--r-- install.d/TODO
  69. #    232 -r--r--r-- install.d/myself.cf
  70. #  15681 -r--r--r-- install.d/special.c
  71. #  16773 -r--r--r-- install.d/dir.c
  72. #   6131 -r--r--r-- install.cf/install.cf.5l
  73. #   6205 -r--r--r-- instck/maxfreq.c
  74. #   3595 -rw-r--r-- instck/Makefile
  75. #    212 -r--r--r-- install.cf/README
  76. #    157 -rw-r--r-- purge/main.h
  77. #   6893 -r--r--r-- purge/filedup.c
  78. #   6261 -r--r--r-- install.d/install.h
  79. #   6676 -rw-r--r-- install.d/configure.h
  80. #   4281 -r--r--r-- instck/instck.1l
  81. #   3262 -r--r--r-- instck/path.c
  82. #   2977 -rw-r--r-- install.d/Makefile
  83. #   4174 -r--r--r-- install.d/README
  84. #   2898 -r--r--r-- install.d/main.h
  85. #   3429 -r--r--r-- install.d/special.h
  86. #   2444 -r--r--r-- purge/purge.8l
  87. #   2394 -rw-r--r-- purge/main.c
  88. #   2197 -rw-r--r-- purge/Makefile.mkcmd
  89. #    837 -rw-r--r-- install.cf/Makefile
  90. #   2372 -r--r--r-- install.d/syscalls.h
  91. #   1580 -r--r--r-- instck/path.h
  92. #   1520 -r--r--r-- instck/gen.h
  93. #   1307 -r--r--r-- instck/README
  94. #   1367 -r--r--r-- purge/purge.m
  95. #   1148 -r--r--r-- purge/purge.h
  96. #   1262 -r--r--r-- install.d/dir.h
  97. #   1611 -r--r--r-- install.d/file.h
  98. #   1018 -r--r--r-- instck/maxfreq.h
  99. #    825 -r--r--r-- purge/filedup.h
  100. #
  101. # ============= INSTALL.02 ==============
  102. if test -f 'INSTALL.02' -a X"$1" != X"-c"; then
  103.     echo 'x - skipping INSTALL.02 (File already exists)'
  104. else
  105. echo 'x - extracting INSTALL.02 (Text)'
  106. sed 's/^X//' << 'Purdue' > 'INSTALL.02' &&
  107. Contains:
  108. X    install(1l)    - update a file or directory with a guaranteed backup
  109. X    instck(1l)    - look for improperly installed files
  110. X    purge(8l)    - remove outdated backup copies of installed programs
  111. X
  112. X
  113. Notes on depends:
  114. X    - libopt.a and libsrtunq.a need not be installed, but it
  115. X      would make life easier if you want other PUCC tools.
  116. X
  117. X    - install needs to be compiled with libopt, but can run on
  118. X      almost any UNIX system
  119. X
  120. X    - instck needs to know where install's source code is,
  121. X      and needs libopt
  122. X
  123. X    - purge needs to know where install's source code is,
  124. X      and needs libopt
  125. X
  126. X
  127. To install these tools:
  128. X
  129. 0\ read the manual pages, see if you want any of them
  130. X
  131. 1\ Edit install.d/configure.h while looking at a hard copy of
  132. X   install.d/install.h (which contains deafult values).
  133. X   You'll want to set DEFGROUP at least ("binary" is a PUCC localism).
  134. X    lpr install.d/install.h
  135. X    vi install.d/configure.h
  136. X
  137. 2\ decide where to install all this stuff, change the destinations in
  138. X   the Makefiles {BIN,LIB,ETC,HEADER}
  139. X    vi */Makefile
  140. X    
  141. 3\ build install, re-edit configure.h as needed, and check install's defaults:
  142. X    (cd install.d && make)
  143. X    install.d/installp -V
  144. X
  145. 4\ if we do not have symbolic links tell instck/Makefile and purge/Makefile
  146. X    vi instck/Makefile purge/Makefile
  147. X
  148. 5\ build instck & purge
  149. X    (cd instck && make)
  150. X    (cd purge && make)
  151. X
  152. 6\ install the tools
  153. X    su
  154. X    (cd install.d && make install)            # as root
  155. X    (cd instck && make install)            #
  156. X    (cd purge && make install)            #
  157. X    exit                        # the root shell
  158. X
  159. 7\ if you have mkcat, install the manual pages
  160. X    su
  161. X    mkcat -v install.d/install.1l install.d/install.cf.5l \
  162. X         instck/instck.1l purge/purge.8l
  163. X    exit
  164. X
  165. 8\ clean up the dirs
  166. X    (cd install.d && make clean)
  167. X    (cd instck && make clean)
  168. X    (cd purge && make clean)
  169. X
  170. kayessbee
  171. --
  172. Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb
  173. Purdue
  174. chmod 0644 INSTALL.02 ||
  175. echo 'restore of INSTALL.02 failed'
  176. Wc_c="`wc -c < 'INSTALL.02'`"
  177. test 1813 -eq "$Wc_c" ||
  178.     echo 'INSTALL.02: original size 1813, current size' "$Wc_c"
  179. fi
  180. # ============= instck/instck.c ==============
  181. if test ! -d 'instck'; then
  182.     echo 'x - creating directory instck'
  183.     mkdir 'instck'
  184. fi
  185. if test -f 'instck/instck.c' -a X"$1" != X"-c"; then
  186.     echo 'x - skipping instck/instck.c (File already exists)'
  187. else
  188. echo 'x - extracting instck/instck.c (Text)'
  189. sed 's/^X//' << 'Purdue' > 'instck/instck.c' &&
  190. /*
  191. X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
  192. X * 47907.  All rights reserved.
  193. X *
  194. X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
  195. X *
  196. X * This software is not subject to any license of the American Telephone
  197. X * and Telegraph Company or the Regents of the University of California.
  198. X *
  199. X * Permission is granted to anyone to use this software for any purpose on
  200. X * any computer system, and to alter it and redistribute it freely, subject
  201. X * to the following restrictions:
  202. X *
  203. X * 1. Neither the authors nor Purdue University are responsible for any
  204. X *    consequences of the use of this software.
  205. X *
  206. X * 2. The origin of this software must not be misrepresented, either by
  207. X *    explicit claim or by omission.  Credit to the authors and Purdue
  208. X *    University must appear in documentation and sources.
  209. X *
  210. X * 3. Altered versions must be plainly marked as such, and must not be
  211. X *    misrepresented as being the original software.
  212. X *
  213. X * 4. This notice may not be removed or altered.
  214. X */
  215. X
  216. /*
  217. X * these routines check the installation of binary (mostly) files    (ksb)
  218. X * we look for glob expressions to match in given directories, and
  219. X * at what modes the matched files have.  If they look OK we say
  220. X * nothing, else we bitch about the errors.
  221. X */
  222. #if !defined(lint)
  223. static char *rcsid = "$Id: instck.c,v 7.7 90/10/22 12:58:56 ksb Exp $";
  224. #endif    /* !lint */
  225. X
  226. #include <sys/param.h>
  227. #include <sys/types.h>
  228. #include <sys/stat.h>
  229. #include <sys/file.h>
  230. #include <sys/time.h>
  231. #include <fstab.h>
  232. #include <a.out.h>
  233. X
  234. #include "configure.h"
  235. #include "install.h"
  236. #include "main.h"
  237. #include "syscalls.h"
  238. #include "special.h"
  239. #include "instck.h"
  240. #include "path.h"
  241. X
  242. #if defined(HPUX7)
  243. #include <checklist.h>
  244. #define fstab        checklist
  245. #define fs_file        fs_dir
  246. #endif
  247. X
  248. #if defined(SYSV)
  249. #include <sgsparam.h>
  250. #endif
  251. #include <ar.h>
  252. X
  253. #if HAVE_RANLIB
  254. #include <ranlib.h>
  255. #endif
  256. X
  257. #if BSDDIR
  258. #include <sys/dir.h>
  259. #else
  260. #include <ndir.h>
  261. #endif
  262. X
  263. #if STRINGS
  264. #include <strings.h>
  265. #else
  266. #include <string.h>
  267. #endif
  268. X
  269. X
  270. #include <stdio.h>
  271. #include <ctype.h>
  272. #include <errno.h>
  273. #include <pwd.h>
  274. #include <grp.h>
  275. X
  276. extern int stat(), lstat();
  277. extern char *calloc(), *malloc();
  278. extern off_t lseek();
  279. X
  280. X
  281. /*
  282. X * remove all the dirs/files that point to the the same file/dir    (ksb)
  283. X * in a choice between two, take the full path name, or the shorter one.
  284. X * return the new argc
  285. X */
  286. int
  287. ElimDups(argc, argv)
  288. int argc;
  289. char **argv;
  290. {
  291. X    auto int i, j, r;
  292. X    auto struct stat *pSTScan;
  293. X
  294. X    pSTScan = (struct stat *)calloc((unsigned)argc, sizeof(struct stat));
  295. X    if ((struct stat *)0 == pSTScan) {
  296. X        (void)fprintf(stderr, "%s: calloc: out of memory\n", progname);
  297. X        exit(1);
  298. X    }
  299. X
  300. X    for (i = 0; i < argc; ++i) {
  301. X        if (-1 == stat(argv[i], & pSTScan[i])) {
  302. X            (void)fprintf(stderr, "%s: stat: %s: %s\n", progname, argv[i], strerror(errno));
  303. X            argv[i] = (char *)0;
  304. X            continue;
  305. X        }
  306. X        for (j = 0; j < i; ++j) {
  307. X            if ((char *)0 == argv[j])
  308. X                continue;
  309. X            if (pSTScan[j].st_ino != pSTScan[i].st_ino)
  310. X                continue;
  311. X            if (pSTScan[j].st_dev != pSTScan[i].st_dev)
  312. X                continue;
  313. X            if (S_IFDIR != (pSTScan[i].st_mode & S_IFMT))
  314. X                continue;
  315. X            if (strlen(argv[j]) < strlen(argv[i])) {
  316. X                r = i;
  317. X                if ('/' != argv[j][0] && '/' == argv[i][0])
  318. X                    r = j;
  319. X            } else {
  320. X                r = j;
  321. X                if ('/' != argv[i][0] && '/' == argv[j][0])
  322. X                    r =i;
  323. X            }
  324. X            if (fVerbose)
  325. X                (void)fprintf(stderr, "%s: `%s\': dup of `%s\' (not scanned)\n", progname, argv[r], argv[r == i ? j : i]);
  326. X            argv[r] = (char *)0;
  327. X        }
  328. X    }
  329. X    free((char *)pSTScan);
  330. X    for (j = 0, i = 0; i < argc; ++i) {
  331. X        if ((char *)0 == argv[i])
  332. X            continue;
  333. X        argv[j++] = argv[i];
  334. X    }
  335. X
  336. X    return j;
  337. }
  338. X
  339. /*
  340. X * called if the glob match code didn't find any new files        (ksb)
  341. X */
  342. void
  343. NoMatches(pcGlob)
  344. char *pcGlob;
  345. {
  346. X    if (fVerbose) {
  347. X        (void)fprintf(fpOut, "%s: no matches for `%s\'\n", progname, pcGlob);
  348. X    }
  349. }
  350. X
  351. /*
  352. X * used in the path module to init the user data field            (ksb)
  353. X */
  354. void
  355. PUInit(pPD)
  356. PATH_DATA *pPD;
  357. {
  358. X    pPD->fseen = 0;
  359. }
  360. X
  361. X
  362. /*
  363. X * find matching files, look in the real file system            (ksb)
  364. X */
  365. int
  366. FileMatch(pcGlob, pcDir, pfiCall)
  367. char *pcGlob, *pcDir;
  368. int (*pfiCall)(/* char * */);
  369. {
  370. X    register DIR *pDI;
  371. X    register struct direct *pDE;
  372. X    register char *pcTail;
  373. X    register char *pcSlash;
  374. X    auto int iRet;
  375. X    auto char acDir[MAXPATHLEN+1];
  376. X    auto struct stat stDir, stEnt;
  377. X
  378. X    if ((DIR *)0 == (pDI = opendir(pcDir))) {
  379. X        return 0;
  380. X    }
  381. X    pcSlash = strchr(pcGlob, '/');
  382. X    if ((char *)0 != pcSlash) {
  383. X        *pcSlash++ = '\000';
  384. X    }
  385. X    (void)strcpy(acDir, pcDir);
  386. X    pcTail = strchr(acDir, '\000');
  387. X    if (pcTail[-1] != '/') {
  388. X        *pcTail++ = '/';
  389. X    }
  390. X    iRet = 0;
  391. X    if ('\000' == *pcGlob) {
  392. X        if (-1 != (fLinks ? LSTAT : stat)(acDir, & stDir)) {
  393. X            iRet = (*pfiCall)(acDir, &stDir);
  394. X        }
  395. X    } else if ((char *)0 == pcSlash) {
  396. X        while (0 == iRet && (struct direct *)0 != (pDE = readdir(pDI))) {
  397. X            if (! _SamePath(pcGlob, pDE->d_name, 1)) {
  398. X                continue;
  399. X            }
  400. X            (void)strcpy(pcTail, pDE->d_name);
  401. X            if ((char *)0 != pcSlash) {
  402. X                pcSlash[-1] = '/';
  403. X            }
  404. X            if (-1 == (fLinks ? LSTAT : stat)(acDir, &stEnt)) {
  405. X                fprintf(stderr, "%s: stat: %s: %s\n", progname, acDir, strerror(errno));
  406. X            } else {
  407. X                iRet = (*pfiCall)(acDir, &stEnt);
  408. X            }
  409. X            if ((char *)0 != pcSlash) {
  410. X                pcSlash[-1] = '\000';
  411. X            }
  412. X        }
  413. X    } else if ('\000' == pcSlash[0]) {    /* "p/" matches dirs only */
  414. X        while (0 == iRet && (struct direct *)0 != (pDE = readdir(pDI))) {
  415. X            if (! _SamePath(pcGlob, pDE->d_name, 1))
  416. X                continue;
  417. X            (void)strcpy(pcTail, pDE->d_name);
  418. X            if (-1 == (fLinks ? LSTAT : stat)(acDir, & stDir))
  419. X                continue;
  420. X            if (S_IFDIR != (stDir.st_mode & S_IFMT))
  421. X                continue;
  422. X            (void)strcat(pcTail, "/");
  423. X            if ((char *)0 != pcSlash) {
  424. X                pcSlash[-1] = '/';
  425. X            }
  426. X            iRet = (*pfiCall)(acDir, & stDir);
  427. X            if ((char *)0 != pcSlash) {
  428. X                pcSlash[-1] = '\000';
  429. X            }
  430. X        }
  431. X    } else {
  432. X        while (0 == iRet && (struct direct *)0 != (pDE = readdir(pDI))) {
  433. X            if (! _SamePath(pcGlob, pDE->d_name, 1))
  434. X                continue;
  435. X            (void)strcpy(pcTail, pDE->d_name);
  436. X            (void)strcat(pcTail, "/");
  437. X            if ((char *)0 != pcSlash) {
  438. X                pcSlash[-1] = '/';
  439. X            }
  440. X            iRet = FileMatch(pcSlash, acDir, pfiCall);
  441. X            if ((char *)0 != pcSlash) {
  442. X                pcSlash[-1] = '\000';
  443. X            }
  444. X        }
  445. X    }
  446. X    closedir(pDI);
  447. X    if ((char *)0 != pcSlash) {
  448. X        *--pcSlash = '/';
  449. X    }
  450. X    return iRet;
  451. }
  452. X
  453. X
  454. /*
  455. X * return either "setuid" or "setgid" if the program is loaded with    (ksb)
  456. X * `#!...' and is currently an unsafe mode
  457. X */
  458. #define    BAD_LEN    2
  459. char *
  460. BadLoad(fdFile, mMode)
  461. int fdFile;
  462. int mMode;
  463. {
  464. X    auto char acLook[8];
  465. X
  466. X    if (-1 == lseek(fdFile, (off_t)0, 0)) {
  467. X        fprintf(stderr, "%s: lseek: %d: %s\n", progname, fdFile, strerror(errno));
  468. X        return (char *)0;
  469. X    }
  470. X    if (BAD_LEN != read(fdFile, &acLook[0], BAD_LEN)) {
  471. X        return (char *)0;
  472. X    }
  473. X    if ('#' != acLook[0] || '!' != acLook[1]) {
  474. X        return (char *)0;
  475. X    }
  476. X    if (0 != (S_ISUID&mMode)) {
  477. X        return "setuid";
  478. X    }
  479. X    if (0 != (S_ISGID*mMode)) {
  480. X        return "setgid";
  481. X    }
  482. X    return (char *)0;
  483. }
  484. #undef BAD_LEN
  485. X
  486. /*
  487. X * is the file in question a binary and stripped?
  488. X * -1 not a binary
  489. X * 0 binary, not stripped
  490. X * 1 binary, stripped
  491. X */
  492. int
  493. IsStripped(fdFile, pstBin)
  494. int fdFile;
  495. struct stat *pstBin;
  496. {
  497. X    auto EXHDR exhd;
  498. X
  499. X    if (S_IFREG != (pstBin->st_mode & S_IFMT)) {
  500. X        /* libs must be plain files */
  501. X        return -1;
  502. X    }
  503. X    if (-1 == lseek(fdFile, (off_t)0, 0)) {
  504. X        fprintf(stderr, "%s: lseek: %d: %s\n", progname, fdFile, strerror(errno));
  505. X        return -1;
  506. X    }
  507. X    if (sizeof(exhd) != read(fdFile, (char *) &exhd, sizeof(exhd))) {
  508. X        return -1;
  509. X    }
  510. X    switch (exhd.MNUMBER) {
  511. #if defined(FMAGIC)
  512. X    case FMAGIC:            /* HP format?            */
  513. #endif
  514. #if defined(OMAGIC)
  515. X    case OMAGIC:            /* old impure format        */
  516. #endif
  517. #if defined(NMAGIC)
  518. X    case NMAGIC:            /* read-only text        */
  519. #endif
  520. #if defined(ZMAGIC)
  521. X    case ZMAGIC:            /* demand load format        */
  522. #endif
  523. #if defined(ETAMAGIC)
  524. X    case ETAMAGIC:            /* eta systems load format    */
  525. #endif
  526. X        if (0 == exhd.MSYMS)
  527. X            return 1;
  528. X        return 0;
  529. X    default:
  530. X        break;
  531. X    }
  532. X    return -1;
  533. }
  534. X
  535. /*
  536. X * is the named file a ar random library                (ksb)
  537. X * Read the ar magic number, is it a library?
  538. X * read the first ar member, is it __.SYMDEF
  539. X * is __.SYMDEF OLDer that the file (only ranlib does this)
  540. X */
  541. int
  542. IsRanlibbed(fdFile, pstLib)
  543. int fdFile;
  544. struct stat *pstLib;
  545. {
  546. X    extern long atol();
  547. #if !defined(SARMAG)
  548. X    static char ar_gross[] = ARMAG;
  549. #define SARMAG (sizeof(ar_gross)-1)
  550. #endif
  551. #if defined(bsd)
  552. X    static char acTOC[] = "__.SYMDEF";
  553. #endif
  554. X    auto char acBuf[SARMAG+10];
  555. X    auto struct ar_hdr arhd;
  556. X
  557. X    if (S_IFREG != (pstLib->st_mode & S_IFMT)) {
  558. X        /* libs must be plain files */
  559. X        return -1;
  560. X    }
  561. X    if (-1 == lseek(fdFile, (off_t)0, 0)) {
  562. X        fprintf(stderr, "%s: lseek: %d: %s\n", progname, fdFile, strerror(errno));
  563. X        return -1;
  564. X    }
  565. X    if (SARMAG != read(fdFile, acBuf, SARMAG)) {
  566. X        return -1;
  567. X    }
  568. X    if (0 != strncmp(ARMAG, acBuf, SARMAG)) {
  569. X        return -1;
  570. X    }
  571. #if defined(bsd)
  572. X    if (sizeof(arhd) != read(fdFile, (char *)& arhd, sizeof(arhd))) {
  573. X        return 0;
  574. X    }
  575. X    if (0 != strncmp(acTOC, arhd.ar_name, sizeof(acTOC)-1)) {
  576. X        return 0;
  577. X    }
  578. X    return pstLib->st_mtime <= atol(arhd.ar_date);
  579. #else
  580. X    return 1;
  581. #endif
  582. }
  583. X
  584. #if BROKEN_CHMOD
  585. static char aaacAdd[8][8][4] =
  586. /* add 0   01    02    03   04    05    06     07      have    */
  587. X  { { "", "x", "w", "wx", "r", "rx", "rw", "rwx"}, /* 00    */
  588. X    { "",  "", "w",  "w", "r",  "r", "rw",  "rw"}, /* 01    */
  589. X    { "", "x",  "",  "x", "r", "rx",  "r",  "rx"}, /* 02    */
  590. X    { "",  "",  "",   "", "r",  "r",  "r",   "r"}, /* 03    */
  591. X    { "", "x", "w", "wx",  "",  "x",  "w",  "wx"}, /* 04    */
  592. X    { "",  "", "w",  "w",  "",   "",  "w",   "w"}, /* 05    */
  593. X    { "", "x",  "",  "x",  "",  "x",   "",   "x"}, /* 06    */
  594. X    { "",  "",  "",   "",  "",   "",   "",    ""}};/* 07    */
  595. X
  596. /*
  597. X * sun's chmod(1) won't take litteral 0755 to change setgid bits    (ksb)
  598. X * so we have to convert such things into symbolic +- forms (yucko)
  599. X *
  600. X * If we exchange the subscripts of the Add matrix we get a subtraction
  601. X * matrix.  See assignments to pcS{Uid,Gid,All} below vs pcA{...}.
  602. X */
  603. static void
  604. SunBotch(pcDo, mFrom, mTo)
  605. char *pcDo;
  606. int mFrom, mTo;
  607. {
  608. X    auto char cUid, cGid, cSticky, cSep;
  609. X    auto char *pcAUid, *pcAGid, *pcAAll;
  610. X    auto char *pcSUid, *pcSGid, *pcSAll;
  611. X
  612. X    cUid = (S_ISUID&mFrom) != (S_ISUID&mTo) ?
  613. X        ((S_ISUID&mTo) ? '+' : '-') : '\000';
  614. X    pcAUid = aaacAdd[(mFrom&0700)>>6][(mTo&0700)>>6];
  615. X    pcSUid = aaacAdd[(mTo&0700)>>6][(mFrom&0700)>>6];
  616. X    cGid = (S_ISGID&mFrom) != (S_ISGID&mTo) ?
  617. X        ((S_ISGID&mTo) ? '+' : '-') : '\000';
  618. X    pcAGid = aaacAdd[(mFrom&0070)>>3][(mTo&0070)>>3];
  619. X    pcSGid = aaacAdd[(mTo&0070)>>3][(mFrom&0070)>>3];
  620. X    cSticky = (S_ISVTX&mFrom) != (S_ISVTX&mTo) ?
  621. X        ((S_ISVTX&mTo) ? '+' : '-') : '\000';
  622. X    pcAAll = aaacAdd[(mFrom&0007)>>0][(mTo&0007)>>0];
  623. X    pcSAll = aaacAdd[(mTo&0007)>>0][(mFrom&0007)>>0];
  624. X    if ('\000' != cUid) {
  625. X        *pcDo++ = 'u';
  626. X        if (cUid == cGid) {
  627. X            cGid = '\000';
  628. X            *pcDo++ = 'g';
  629. X        }
  630. X        *pcDo++ = cUid;
  631. X        *pcDo++ = 's';
  632. X        if (cUid == cSticky) {
  633. X            *pcDo++ = 't';
  634. X            cSticky = '\000';
  635. X        }
  636. X        cSep = ',';
  637. X    } else {
  638. X        cSep = '\000';
  639. X    }
  640. X    if ('\000' != cGid) {
  641. X        if ('\000' != cSep)
  642. X            *pcDo++ = cSep;
  643. X        *pcDo++ = 'g';
  644. X        *pcDo++ = cGid;
  645. X        *pcDo++ = 's';
  646. X        cSep = ',';
  647. X    }
  648. X    if ('\000' != cSticky) {
  649. X        if ('\000' != cSep)
  650. X            *pcDo++ = cSep;
  651. X        *pcDo++ = cSticky;
  652. X        *pcDo++ = 't';
  653. X        cSep = ',';
  654. X    }
  655. X    if ('\000' != pcAUid[0]) {
  656. X        if ('\000' != cSep)
  657. X            *pcDo++ = cSep;
  658. X        *pcDo++ = 'u';
  659. X        if (0 == strcmp(pcAGid, pcAUid)) {
  660. X            *pcDo++ = 'g';
  661. X            pcAGid = "";
  662. X        }
  663. X        if (0 == strcmp(pcAAll, pcAUid)) {
  664. X            *pcDo++ = 'o';
  665. X            pcAAll = "";
  666. X        }
  667. X        *pcDo++ = '+';
  668. X        (void)strcpy(pcDo, pcAUid);
  669. X        pcDo += strlen(pcDo);
  670. X        cSep = ',';
  671. X    }
  672. X    if ('\000' != pcSUid[0]) {
  673. X        if ('\000' != cSep)
  674. X            *pcDo++ = cSep;
  675. X        *pcDo++ = 'u';
  676. X        if (0 == strcmp(pcSGid, pcSUid)) {
  677. X            *pcDo++ = 'g';
  678. X            pcSGid = "";
  679. X        }
  680. X        if (0 == strcmp(pcSAll, pcSUid)) {
  681. X            *pcDo++ = 'o';
  682. X            pcSAll = "";
  683. X        }
  684. X        *pcDo++ = '-';
  685. X        (void)strcpy(pcDo, pcSUid);
  686. X        pcDo += strlen(pcDo);
  687. X        cSep = ',';
  688. X    }
  689. X    if ('\000' != pcAGid[0]) {
  690. X        if ('\000' != cSep)
  691. X            *pcDo++ = cSep;
  692. X        *pcDo++ = 'g';
  693. X        if (0 == strcmp(pcAAll, pcAGid)) {
  694. X            *pcDo++ = 'o';
  695. X            pcAAll = "";
  696. X        }
  697. X        *pcDo++ = '+';
  698. X        (void)strcpy(pcDo, pcAGid);
  699. X        pcDo += strlen(pcDo);
  700. X        cSep = ',';
  701. X    }
  702. X    if ('\000' != pcSGid[0]) {
  703. X        if ('\000' != cSep)
  704. X            *pcDo++ = cSep;
  705. X        *pcDo++ = 'g';
  706. X        if (0 == strcmp(pcSAll, pcSGid)) {
  707. X            *pcDo++ = 'o';
  708. X            pcSAll = "";
  709. X        }
  710. X        *pcDo++ = '-';
  711. X        (void)strcpy(pcDo, pcSGid);
  712. X        pcDo += strlen(pcDo);
  713. X        cSep = ',';
  714. X    }
  715. X    if ('\000' != pcAAll[0]) {
  716. X        if ('\000' != cSep)
  717. X            *pcDo++ = cSep;
  718. X        *pcDo++ = 'o';
  719. X        *pcDo++ = '+';
  720. X        (void)strcpy(pcDo, pcAAll);
  721. X        pcDo += strlen(pcDo);
  722. X        cSep = ',';
  723. X    }
  724. X    if ('\000' != pcSAll[0]) {
  725. X        if ('\000' != cSep)
  726. X            *pcDo++ = cSep;
  727. X        *pcDo++ = 'o';
  728. X        *pcDo++ = '-';
  729. X        (void)strcpy(pcDo, pcSAll);
  730. X        pcDo += strlen(pcDo);
  731. X        cSep = ',';
  732. X    }
  733. X    *pcDo = '\000';
  734. }
  735. #endif /* brain dead chmod(2) */
  736. X
  737. X
  738. /*
  739. X * qwery the user and exec the `fix' program, if he wants to        (ksb)
  740. X *
  741. X * We tell RunCmd to be quiet, because we echo the command when
  742. X * we prompt for run/not.  Return 1 for `skip the rest of this file'.
  743. X */
  744. static int
  745. QExec(cmd, arg1, arg2, pcWas)
  746. char *cmd, *arg1, *arg2, *pcWas;
  747. {
  748. X    auto char **ppc;
  749. X    auto char *arg0, *pcTemp;
  750. X    auto char acAns[MAXANS+1];
  751. X    auto int iSave;
  752. X    static char *apcHelp[] = {
  753. X        "f\tskip to the next file",
  754. X        "h\tprint this help message",
  755. X        "n\tdo not run this command",
  756. X        "y\trun this command",
  757. X        "q\tquit the program",
  758. X        (char *)0
  759. X    };
  760. X
  761. X    arg0 = StrTail(cmd);
  762. X    for (;;) {
  763. X        (void)fprintf(fpOut, "%s: %s %s", progname, arg0, arg1);
  764. X        if ((char *)0 != arg2)
  765. X            (void)printf(" %s", arg2);
  766. X        if ((char *)0 != pcWas)
  767. X            (void)printf(" {was %s}", pcWas);
  768. X        fputs(" [nfhqy] ", fpOut);
  769. X
  770. X        if ((char *)0 == fgets(acAns, MAXANS, stdin)) {
  771. X            (void)clearerr(stdin);
  772. X            fputs("[EOF]\n", fpOut);
  773. X            return 0;
  774. X        }
  775. X        pcTemp = acAns;
  776. X        while (isspace(*pcTemp) && '\n' != *pcTemp)
  777. X            ++pcTemp;
  778. X        switch (*pcTemp) {
  779. X        default:
  780. X            (void)fprintf(stderr, "%s: unknown execute key `%c\'\n", progname, *pcTemp);
  781. X        case 'h':
  782. X        case 'H':
  783. X        case '?':
  784. X            for (ppc = apcHelp; (char *)0 != *ppc; ++ppc) {
  785. X                (void)fprintf(fpOut, "%s\n", *ppc);
  786. X            }
  787. X            continue;
  788. X        case 'y':    /* yeah, run it    */
  789. X        case 'Y':
  790. X            iSave = fTrace;
  791. X            fTrace = FALSE;
  792. X            (void)RunCmd(cmd, arg1, arg2);
  793. X            fTrace = iSave;
  794. #if defined(INST_FACILITY)
  795. X            if (bHaveRoot) {
  796. X                if ((char *)0 == arg2) {
  797. X                    if ((char *)0 == pcWas)
  798. X                        syslog(LOG_INFO, "%s %s by %s", arg0, arg1, pcGuilty);
  799. X                    else
  800. X                        syslog(LOG_INFO, "%s %s {was %s} by %s", arg0, arg1, pcWas, pcGuilty);
  801. X                } else if ((char *)0 == pcWas) {
  802. X                    syslog(LOG_INFO, "%s %s %s by %s", arg0, arg1, arg2, pcGuilty);
  803. X                } else {
  804. X                    syslog(LOG_INFO, "%s %s %s {was %s} by %s", arg0, arg1, arg2, pcWas, pcGuilty);
  805. X                }
  806. X            }
  807. #endif
  808. X            break;
  809. X
  810. X        case 'q':    /* quit this    */
  811. X        case 'Q':
  812. X            exit(0);
  813. X
  814. X        case '\n':
  815. X        case 'n':    /* no thanks    */
  816. X        case 'N':
  817. X            break;
  818. X
  819. X        case 'f':    /* next file    */
  820. X        case 'F':
  821. X            return 1;
  822. X        }
  823. X        break;
  824. X    }
  825. X    return 0;
  826. X
  827. }
  828. X
  829. CHLIST CLCheck;
  830. static COMPONENT *pCMRoot;
  831. int iMatches;
  832. X
  833. /*
  834. X * we are passed a filename that exists and matches the recorded
  835. X * install.cf line our parrent is currently working one.  We should
  836. X * look in the list of examined files to see if we have already
  837. X * matched this file, if so we can ignore this match.  Else check to
  838. X * see if it would pass the current line.
  839. X * Report bugs to stdout as install(1l) would, or close.
  840. X */
  841. int
  842. DoCk(pcFile, pstThis)
  843. char *pcFile;
  844. struct stat *pstThis;
  845. {
  846. X    register PATH_DATA *pPD;
  847. X    auto int fdFile;
  848. X    auto int fChGroup, fChOwner, fChMode;
  849. X    auto char acOOwner[128], acOGroup[128], acOMode[128];
  850. X    auto char acNMode[128];
  851. X    auto int mMode, mNew;
  852. X
  853. X    pPD = AddPath(& pCMRoot, pcFile);
  854. X    if (0 != pPD->fseen) {
  855. X        return 0;
  856. X    }
  857. X    pPD->fseen = 1;
  858. X    ++iMatches;
  859. X
  860. X    if ('~' == CLCheck.acmode[0]) {
  861. X        (void)fprintf(fpOut, "%s: `%s\' should not be installed\n", progname, pcFile);
  862. X    } else if ('!' == CLCheck.acmode[0]) {
  863. X        (void)fprintf(fpOut, "%s: `%s\' should not exist\n", progname, pcFile);
  864. X        if (fInteract) {
  865. X            if (QExec(BINRM, "-f", pcFile, (char *)0 != CLCheck.pcmesg && '\000' != CLCheck.pcmesg[0] ? CLCheck.pcmesg : NodeType(pstThis->st_mode, (char *)0))) {
  866. X                return 0;
  867. X            }
  868. X            /* if the user didn't remove it, check it
  869. X             */
  870. X            if (-1 == access(pcFile, 0)) {
  871. X                return 0;
  872. X            }
  873. X        } else {
  874. X            return 0;
  875. X        }
  876. X    }
  877. X    if ('*' == CLCheck.acmode[0]) {
  878. X        /* nothing */;
  879. X    } else if (CLCheck.mtype != (pstThis->st_mode & S_IFMT)) {
  880. X        (void)fprintf(fpOut, "%s: `%s\' should be a %s, not a %s\n", progname, pcFile, NodeType(CLCheck.mtype, (char *)0), NodeType(pstThis->st_mode, (char *)0));
  881. X        return 0;
  882. X    }
  883. X
  884. X    /* time to check the group, owner, mode against our check list...
  885. X     * We buffer all the info up for one big informative printf at the end
  886. X     */
  887. X    fChOwner = fChGroup = fChMode = FALSE;
  888. X
  889. X    if ('*' == CLCheck.acowner[0] || (CLCheck.fbangowner ? (fChOwner = pstThis->st_uid == CLCheck.uid) : (fChOwner = pstThis->st_uid != CLCheck.uid))) {
  890. X        register struct passwd *pwdTemp;
  891. X
  892. X        pwdTemp = getpwuid(pstThis->st_uid);
  893. X        if ((struct passwd *)0 != pwdTemp) {
  894. X            (void)strcpy(acOOwner, pwdTemp->pw_name);
  895. X        } else {
  896. X            (void)sprintf(acOOwner, "%d", pstThis->st_uid);
  897. X        }
  898. X    } else {
  899. X        (void)strcpy(acOOwner, CLCheck.acowner);
  900. X    }
  901. X
  902. X    if ('*' == CLCheck.acgroup[0] || (CLCheck.fbanggroup ? (fChGroup = pstThis->st_gid == CLCheck.gid) : (fChGroup = pstThis->st_gid != CLCheck.gid))) {
  903. X        register struct group *grpTemp;
  904. X
  905. X        grpTemp = getgrgid(pstThis->st_gid);
  906. X        if ((struct group *)0 != grpTemp) {
  907. X            (void)strcpy(acOGroup, grpTemp->gr_name);
  908. X        } else {
  909. X            (void)sprintf(acOGroup, "%d", pstThis->st_gid);
  910. X        }
  911. X    } else {
  912. X        (void)strcpy(acOGroup, CLCheck.acgroup);
  913. X    }
  914. X
  915. X    mMode = PERM_BITS(pstThis->st_mode);
  916. X    (void)sprintf(acOMode, "%04o", mMode);
  917. X    if ('*' != CLCheck.acmode[0]) {
  918. X        if (CLCheck.mmust != (mMode & CLCheck.mmust)) {
  919. X            fChMode = 1;
  920. X        } else if (0 != (mMode &~ (CLCheck.mmust|CLCheck.moptional))) {
  921. X            fChMode = 1;
  922. X        }
  923. X        mNew = CLCheck.mmust | (mMode & CLCheck.moptional);
  924. X        if (0 != (S_ISUID & mMode) ? 0 == (S_ISUID & (CLCheck.mmust|CLCheck.moptional)) : 0 != (S_ISUID & CLCheck.mmust)) {
  925. X            if (fVerbose) {
  926. X                (void)fprintf(fpOut, "%s: `%s\' setuid bit must be %s\n", progname, pcFile, apcOO[0 == (S_ISUID & mMode)]);
  927. X            }
  928. X            mNew |= (S_ISUID & (CLCheck.mmust|CLCheck.moptional));
  929. X            fChMode = 1;
  930. X        }
  931. X        if (0 != (S_ISGID & mMode) ? 0 == (S_ISGID & (CLCheck.mmust|CLCheck.moptional)) : 0 != (S_ISGID & CLCheck.mmust)) {
  932. X            if (fVerbose) {
  933. X                (void)fprintf(fpOut, "%s: `%s\' setgid bit must be %s\n", progname, pcFile, apcOO[0 == (S_ISGID & mMode)]);
  934. X            }
  935. X            mNew |= (S_ISGID & (CLCheck.mmust|CLCheck.moptional));
  936. X            fChMode = 1;
  937. X        }
  938. X        if (0 != (S_ISVTX & mMode) ? 0 == (S_ISVTX & (CLCheck.mmust|CLCheck.moptional)) : 0 != (S_ISVTX & CLCheck.mmust)) {
  939. X            if (fVerbose) {
  940. X                (void)fprintf(fpOut, "%s: `%s\' sticky bit must be %s\n", progname, pcFile, apcOO[0 == (S_ISVTX & mMode)]);
  941. X            }
  942. X            mNew |= (S_ISVTX & (CLCheck.mmust|CLCheck.moptional));
  943. X            fChMode = 1;
  944. X        }
  945. #if BROKEN_CHMOD
  946. X        if (fChMode) {
  947. X            SunBotch(acNMode, mMode, mNew);
  948. X        } else {
  949. X            (void)sprintf(acNMode, "%04o", mNew);
  950. X        }
  951. #else
  952. X        (void)sprintf(acNMode, "%04o", mNew);
  953. #endif
  954. X    } else {
  955. X        (void)strcpy(acNMode, CLCheck.acmode);
  956. X    }
  957. X
  958. X    /* tell the user of their sins, ask if they want to repent
  959. X     */
  960. X    if (fChOwner || fChGroup || fChMode) {
  961. X        fprintf(fpOut, "%s: `%s\' is %s.%s(%s) should be %s%s.%s%s(%s)\n", progname, pcFile, acOOwner, acOGroup, acOMode, CLCheck.fbangowner ? "!" : "", CLCheck.acowner, CLCheck.fbanggroup ? "!" : "", CLCheck.acgroup, acNMode);
  962. X    }
  963. X    if (fInteract) {
  964. X        if (fChOwner && !CLCheck.fbangowner && QExec(BINCHOWN, CLCheck.acowner, pcFile, acOOwner)) {
  965. X            return 0;
  966. X        }
  967. X        if (fChGroup && !CLCheck.fbanggroup && QExec(BINCHGRP, CLCheck.acgroup, pcFile, acOGroup)) {
  968. X            return 0;
  969. X        }
  970. X        if (fChMode && QExec(BINCHMOD, acNMode, pcFile, acOMode)) {
  971. X            return 0;
  972. X        }
  973. X        mMode = mNew;    /* guess that the user did change mode LLL */
  974. X    }
  975. X
  976. X    /* if we don't have to check strip/ranlib, don't open the file
  977. X     * if opening the file might activate a device, avoid it.
  978. X     */
  979. X    if ('*' == CLCheck.chstrip && 0 == ((S_ISUID|S_ISGID)&mMode)) {
  980. X        return 0;
  981. X    }
  982. X    if (S_IFREG != (pstThis->st_mode & S_IFMT)) {
  983. X        if (!CF_IS_NONE(CLCheck)) {
  984. X            (void)fprintf(stderr, "%s: %s: will not open %s\n", progname, pcFile, NodeType(pstThis->st_mode, (char *)0));
  985. X        }
  986. X        return 0;
  987. X    }
  988. X
  989. X    if (0 > (fdFile = open(pcFile, 0, 0000))) {
  990. X        if (errno != EACCES) {
  991. X            (void)fprintf(stderr, "%s: open: %s: %s\n", progname, pcFile, strerror(errno));
  992. X        }
  993. X        if (fVerbose) {
  994. X            (void)fprintf(fpOut, "%s: %s: cannot check `%c' flag\n", progname, pcFile, CLCheck.chstrip);
  995. X        }
  996. X        return 0;
  997. X    }
  998. X    if (0 != ((S_ISUID|S_ISGID)&mMode)) {
  999. X        register char *pcBad;
  1000. X        if ((char *)0 != (pcBad = BadLoad(fdFile, mMode))) {
  1001. X            fprintf(stderr, "%s: `%s\' is %s and loaded with `#!...\'!\n", progname, pcFile, pcBad);
  1002. X        }
  1003. X    }
  1004. X    switch (CLCheck.chstrip) {
  1005. X    case CF_ANY:    /* if is set%cid we can get here */
  1006. X        break;
  1007. X    default:
  1008. X        fprintf(stderr, "%s: bad strip flag %c\n", progname, CLCheck.chstrip);
  1009. X        break;
  1010. X    case CF_STRIP:
  1011. X        switch (IsStripped(fdFile, pstThis)) {
  1012. X        case -1:
  1013. X            (void)fprintf(fpOut, "%s: `%s\' is not even a binary, should be stripped?\n", progname, pcFile);
  1014. X            break;
  1015. X        case 0:
  1016. X            (void)fprintf(fpOut, "%s: `%s\' is not strip\'ed\n", progname, pcFile);
  1017. X            if (fInteract && QExec(BINSTRIP, pcFile, (char *)0, "not stripped")) {
  1018. X                (void)close(fdFile);
  1019. X                return 0;
  1020. X            }
  1021. X            break;
  1022. X        case 1:
  1023. X            break;
  1024. X        }
  1025. X        break;
  1026. X    case CF_RANLIB:
  1027. X        if (1 != IsRanlibbed(fdFile, pstThis)) {
  1028. X            register int f;
  1029. X            (void)fprintf(fpOut, "%s: `%s\' is not ranlib\'ed", progname, pcFile);
  1030. X            if (-1 != (f = IsStripped(fdFile, pstThis))) {
  1031. X                (void)fprintf(fpOut, ", it is actually a%s binary\n", f ? " strip\'ed" : "");
  1032. X            } else if (fInteract) {
  1033. X                (void)fputc('\n', fpOut);
  1034. X                if (QExec(BINRANLIB, pcFile, (char *)0, "not ranlibbed")) {
  1035. X                    (void)close(fdFile);
  1036. X                    return 0;
  1037. X                }
  1038. X            } else {
  1039. X                (void)fputc('\n', fpOut);
  1040. X            }
  1041. X        }
  1042. X        break;
  1043. X    case CF_NONE:
  1044. X        switch (IsStripped(fdFile, pstThis)) {
  1045. X        case -1:        /* not a binary        */
  1046. X            switch (IsRanlibbed(fdFile, pstThis)) {
  1047. X            case -1:    /* not a lib.a        */
  1048. X            case 0:        /* no table of contents    */
  1049. X                break;
  1050. X            case 1:
  1051. X                (void)fprintf(fpOut, "%s: `%s\' is ranlib\'ed\n", progname, pcFile);
  1052. X                break;
  1053. X            }
  1054. X            break;
  1055. X        case 0:            /* plain binary        */
  1056. X            break;
  1057. X        case 1:            /* stripped binary    */
  1058. X            (void)fprintf(fpOut, "%s: `%s\' is strip\'ed \n", progname, pcFile);
  1059. X            break;
  1060. X        }
  1061. X        break;
  1062. X    }
  1063. X    (void)close(fdFile);
  1064. X
  1065. X    return 0;
  1066. }
  1067. X
  1068. /*
  1069. X * check for files that were not checked                (ksb)
  1070. X */
  1071. int
  1072. LeftCk(pcFile, pstThis)
  1073. char *pcFile;
  1074. struct stat *pstThis;
  1075. {
  1076. X    auto PATH_DATA *pPD;
  1077. X    auto char *pcType;
  1078. X    auto char acMode[100];
  1079. X
  1080. X    pPD = AddPath(& pCMRoot, pcFile);
  1081. X    if (0 != pPD->fseen) {
  1082. X        return 0;
  1083. X    }
  1084. X    pPD->fseen = 1;
  1085. X
  1086. X    pcType = NodeType(pstThis->st_mode, & acMode[0]);
  1087. X    if (0 != (pstThis->st_mode & 07022)) {
  1088. X        ModetoStr(acMode+1, (int)PERM_BITS(pstThis->st_mode), 0000);
  1089. X        fprintf(fpOut, "%s: `%s\' unchecked %s, mode %s (%04o)\n", progname, pcFile, pcType, acMode, PERM_BITS(pstThis->st_mode));
  1090. X    } else if (fLongList) {
  1091. X        fprintf(fpOut, "%s: `%s\' unchecked %s\n", progname, pcFile, pcType);
  1092. X    }
  1093. X    return 0;
  1094. }
  1095. X
  1096. /*
  1097. X * sep the dirs and the files, dirCk the dirs, fileck file files    (ksb)
  1098. X */
  1099. void
  1100. InstCk(argc, argv, pcLSpecial, pCLCheck)
  1101. int argc;
  1102. char **argv, *pcLSpecial;
  1103. CHLIST *pCLCheck;        /* the checklist buffer DoCk uses    */
  1104. {
  1105. X    register int i, j, fSave;
  1106. X    auto struct stat statb_me;
  1107. X
  1108. X    fSave = fVerbose;
  1109. X    fVerbose = 0;
  1110. X    for (j = i = 0; i< argc; ++i) {
  1111. X        if (-1 == stat(argv[i], &statb_me)) {
  1112. X            fprintf(stderr, "%s: stat: %s: %s\n", progname, argv[i], strerror(errno));
  1113. X            continue;
  1114. X        }
  1115. X        Special(argv[i], pcLSpecial, pCLCheck);
  1116. X        if (S_IFDIR == (statb_me.st_mode & S_IFMT)) {
  1117. X            argv[j++] = argv[i];
  1118. X            if (pCLCheck->ffound)
  1119. X                DoCk(argv[i], & statb_me);
  1120. X            continue;
  1121. X        }
  1122. X        if (pCLCheck->ffound)
  1123. X            DoCk(argv[i], & statb_me);
  1124. X        else
  1125. X            printf("%s: `%s\' not in checklist %s\n", progname, argv[i], pcLSpecial);
  1126. X    }
  1127. X    fVerbose = fSave;
  1128. X
  1129. X    if (!fDirs)
  1130. X        return;
  1131. X    DirCk(j, argv, pcLSpecial, pCLCheck);
  1132. X    OldCk(j, argv, pCLCheck);
  1133. X    for (i = 0; i < j; ++i) {
  1134. X        FileMatch("*", argv[i], LeftCk);
  1135. X    }
  1136. }
  1137. X
  1138. X
  1139. /*
  1140. X * find all the links in a binary dir to a given file in an OLD dir    (ksb)
  1141. X */
  1142. void
  1143. FixLinks(pcDir, pcOld, pcBackFile, pST)
  1144. char *pcDir, *pcOld,  *pcBackFile;
  1145. struct stat *pST;
  1146. {
  1147. X    register DIR *pDI;
  1148. X    register struct direct *pDE;
  1149. X    register int i, j, fLoop, iCount;
  1150. X    register char ch;
  1151. X    register struct fstab *pFS;
  1152. X    auto struct stat statb_inst, statb_of;
  1153. X    auto char acLoop[MAXPATHLEN+1];
  1154. X    auto char acRelink[MAXPATHLEN+1];
  1155. X
  1156. X    (void)sprintf(acLoop, "../%s", pcBackFile);
  1157. X    /* strip off the mktemp suffix?
  1158. X     */
  1159. X    i = strlen(acLoop);
  1160. X    j = i - 7;
  1161. X    if (j < 4)
  1162. X        j = 4;
  1163. X    for (ch = '\000'; i > j; acLoop[i] = ch, --i, ch = acLoop[i], acLoop[i] = '\000') {
  1164. X        if ('\000' !=ch && !isdigit(ch) &&
  1165. X            (! isalpha(ch) && !isdigit(acLoop[i+1]))) {
  1166. X            acLoop[i] = ch;
  1167. X            i = j;
  1168. X            break;
  1169. X        }
  1170. X        if (-1 == stat(acLoop, & statb_of)) {
  1171. X            if (ENOENT == errno)
  1172. X                continue;
  1173. X            (void)fprintf(stderr, "%s: stat: %s: %s\n", progname, acLoop, strerror(errno));
  1174. X            i = j;
  1175. X            break;
  1176. X        }
  1177. X        break;
  1178. X    }
  1179. X    if (i != j && pST->st_ino == statb_of.st_ino &&
  1180. X        pST->st_dev == statb_of.st_dev) {
  1181. X        fLoop = 1;
  1182. X        (void)fprintf(fpOut, "%s: `%s/%s\' is still linked to backup %s/%s/%s (inode %d)\n", progname, pcDir, acLoop+3, pcDir, pcOld, pcBackFile, pST->st_ino);
  1183. X    } else {
  1184. X        fLoop = 0;
  1185. X        (void)fprintf(fpOut, "%s: `%s/%s/%s\' has too many links (inode %d)\n", progname, pcDir, pcOld, pcBackFile, pST->st_ino);
  1186. X    }
  1187. X    iCount = fLoop + 1;
  1188. X
  1189. X    if ((DIR *)0 == (pDI = opendir(".."))) {
  1190. X        (void)fprintf(stderr, "%s: opendir: ..: %s\n", progname, strerror(errno));
  1191. X        return;
  1192. X    }
  1193. X    while ((struct direct *)0 != (pDE = readdir(pDI))) {
  1194. X        if ('.' == pDE->d_name[0] && ('\000' == pDE->d_name[1] ||
  1195. X           ('.' == pDE->d_name[1] && '\000' == pDE->d_name[2])))
  1196. X            continue;
  1197. X        if (i != j && 0 == strcmp(acLoop+3, pDE->d_name)) {
  1198. X            continue;
  1199. X        }
  1200. X        (void)sprintf(acRelink, "../%s", pDE->d_name);
  1201. X        if (-1 == LSTAT(acRelink, &statb_inst)) {
  1202. X            if (ENOENT == errno)
  1203. X                continue;
  1204. X            (void)fprintf(stderr, "%s: lstat: %s: %s\n", progname, acRelink, strerror(errno));
  1205. X            continue;
  1206. X        }
  1207. X        if (pST->st_ino != statb_inst.st_ino ||
  1208. X            pST->st_dev != statb_inst.st_dev) {
  1209. X            continue;
  1210. X        }
  1211. X        ++iCount;
  1212. X        if (i == j) {
  1213. X            if (fInteract) {
  1214. X                (void)fprintf(fpOut, "%s: removing %s, a bogus link to %s (cwd=%s/%s)\n", progname, acRelink, pcBackFile, pcDir, pcOld);
  1215. X                (void)QExec(BINRM, "-f", acRelink, "a bogus link");
  1216. X            } else {
  1217. X                (void)fprintf(fpOut, "%s: `%s/%s\' is a link to %s/%s/%s\n", progname, pcDir, pDE->d_name, pcDir, pcOld, pcBackFile);
  1218. X            }
  1219. X            continue;
  1220. X        }
  1221. X        if (fLoop) {
  1222. X            (void)fprintf(fpOut, "%s: `%s/%s\' is a link to %s/%s/%s\n", progname, pcDir, pDE->d_name, pcDir, pcOld, pcBackFile);
  1223. X            continue;
  1224. X        }
  1225. X        if (fInteract) {
  1226. X            (void)fprintf(fpOut, "%s: linking %s to %s (cwd=%s/%s)\n", progname, acRelink, acLoop, pcDir, pcOld);
  1227. X            if (!QExec(BINRM, "-f", acRelink, "link into OLD"))
  1228. X                (void)QExec(BINLN, acLoop, acRelink, (char *)0);
  1229. X            continue;
  1230. X        }
  1231. X        (void)fprintf(fpOut, "%s: `%s/%s\' should be linked to `%s/%s\'\n", progname, pcDir, pDE->d_name, pcDir, acLoop+3);
  1232. X    }
  1233. X    (void)closedir(pDI);
  1234. X    /* have seen all the links
  1235. X     */
  1236. X    if (pST->st_nlink == iCount)
  1237. X        return;
  1238. X
  1239. X    /* find the mount point for this file system
  1240. X     */
  1241. X    (void)setfsent();
  1242. X    while ((struct fstab *)0 != (pFS = getfsent())) {
  1243. X        if ('.' == pFS->fs_file[0] && '\000' == pFS->fs_file[1])
  1244. X            continue;    /* ignore me */
  1245. X        if (-1 == stat(pFS->fs_file, &statb_of))
  1246. X            continue;
  1247. X        if (statb_of.st_dev != pST->st_dev)
  1248. X            continue;
  1249. X        /* found it */
  1250. X        (void)fprintf(fpOut, "%s: use `find %s -inum %d -print\' to locate missing links\n", progname, pFS->fs_file, pST->st_ino);
  1251. X        iCount = pST->st_nlink;
  1252. X        break;
  1253. X    }
  1254. X    (void)endfsent();
  1255. X    if (pST->st_nlink != iCount) {
  1256. X        (void)fprintf(fpOut, "%s: %s: count not find mount point\n", progname, pcDir);
  1257. X    }
  1258. }
  1259. X
  1260. X
  1261. static char
  1262. X    *pcOldOwner = ODIROWNER,
  1263. X    *pcOldGroup = ODIRGROUP,
  1264. X    *pcOldMode = ODIRMODE,
  1265. X    acOld[] = OLDDIR;
  1266. X
  1267. /*
  1268. X * check the OLD dirs for pooly installed files                (ksb)
  1269. X */
  1270. void
  1271. OldCk(iCount, ppcDirs, pCLCheck)
  1272. int iCount;
  1273. char **ppcDirs;
  1274. CHLIST *pCLCheck;        /* the checklist buffer DoCk uses    */
  1275. {
  1276. X    register DIR *pDI;
  1277. X    register struct direct *pDE;
  1278. X    register int i, fChMode;
  1279. X    auto char acMode[64];
  1280. X    auto char acPwd[MAXPATHLEN+1];
  1281. X    auto struct stat statb_backup, statb_old, statb_dir;
  1282. X    auto struct passwd *pwdOldDef;
  1283. X    auto struct group *grpOldDef;
  1284. X    auto int mOldMust, mOldQuest;
  1285. X
  1286. X    if ((char *)0 == getwd(acPwd)) {
  1287. X        (void)fprintf(stderr, "%s: %s\n", progname, acPwd);
  1288. X        exit(99);
  1289. X    }
  1290. X
  1291. X    if (!bHaveRoot) {
  1292. X        pwdOldDef = getpwuid(geteuid());
  1293. X        if ((struct passwd *)0 == pwdOldDef) {
  1294. X            fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, geteuid(), strerror(errno));
  1295. X            exit(10);
  1296. X        }
  1297. X        pwdOldDef = savepwent(pwdOldDef);
  1298. X        pcOldOwner = pwdOldDef->pw_name;
  1299. X    } else if ((char *)0 != pcOldOwner || '\000' == pcOldOwner[0]) {
  1300. X        pcOldOwner = (char *)0;
  1301. X        pwdOldDef = (struct passwd *)0;
  1302. X    } else {
  1303. X        pwdOldDef = getpwnam(pcOldOwner);
  1304. X        if ((struct passwd *)0 == pwdOldDef) {
  1305. X            fprintf(stderr, "%s: getpwname: %s: %s\n", progname, pcOldOwner, strerror(errno));
  1306. X            exit(10);
  1307. X        }
  1308. X        pwdOldDef = savepwent(pwdOldDef);
  1309. X    }
  1310. X    if (!bHaveRoot) {
  1311. X        grpOldDef = getgrgid(getegid());
  1312. X        if ((struct group *)0 == grpOldDef) {
  1313. X            fprintf(stderr, "%s: getgrgid: %d: %s\n", progname, getegid(), strerror(errno));
  1314. X            exit(10);
  1315. X        }
  1316. X        grpOldDef = savegrent(grpOldDef);
  1317. X        pcOldGroup = grpOldDef->gr_name;
  1318. X    } else if ((char *)0 == pcOldGroup || '\000' == pcOldGroup[0]) {
  1319. X        pcOldGroup = (char *)0;
  1320. X        grpOldDef = (struct group *)0;
  1321. X    } else {
  1322. X        grpOldDef = getgrnam(pcOldGroup);
  1323. X        if ((struct group *)0 == grpOldDef) {
  1324. X            fprintf(stderr, "%s: getgrname: %s: %s\n", progname, pcOldGroup, strerror(errno));
  1325. X            exit(10);
  1326. X        }
  1327. X        grpOldDef = savegrent(grpOldDef);
  1328. X    }
  1329. X    if ((char *)0 == pcOldMode || '\000' == pcOldMode[0]) {
  1330. X        pcOldMode = (char *)0;
  1331. X    } else {
  1332. X        CvtMode(pcOldMode, &mOldMust, &mOldQuest);
  1333. X    }
  1334. X
  1335. X    for (i = 0; i < iCount; ++i, chdir(acPwd)) {
  1336. X        auto char acCurOld[MAXPATHLEN+2];
  1337. X
  1338. X        if ('/' == ppcDirs[i][0]) {        /* full path to it */
  1339. X            (void)sprintf(acCurOld, "%s/%s", ppcDirs[i], acOld);
  1340. X        } else {
  1341. X            (void)sprintf(acCurOld, "%s/%s/%s", acPwd, ppcDirs[i], acOld);
  1342. X        }
  1343. X        if (-1 == stat(ppcDirs[i], & statb_dir)) {
  1344. X            (void)fprintf(fpOut, "%s: stat: %s: %s\n", progname, ppcDirs[i], strerror(errno));
  1345. X            continue;
  1346. X        }
  1347. X
  1348. X        /* check the modes on the OLD directory itself
  1349. X         */
  1350. X        if ((char *)0 == pcOldOwner) {
  1351. X            register struct passwd *pwdTemp;
  1352. X
  1353. X            pCLCheck->uid = statb_dir.st_uid;
  1354. X            pwdTemp = getpwuid(statb_dir.st_uid);
  1355. X            if ((struct passwd *)0 != pwdTemp) {
  1356. X                (void)strcpy(pCLCheck->acowner, pwdTemp->pw_name);
  1357. X            } else {
  1358. X                (void)sprintf(pCLCheck->acowner, "%d", statb_dir.st_uid);
  1359. X            }
  1360. X        } else {    /* yeah, this is an invarient */
  1361. X            pCLCheck->uid = pwdOldDef->pw_uid;
  1362. X            (void)strcpy(pCLCheck->acowner, pwdOldDef->pw_name);
  1363. X        }
  1364. X        if ((char *)0 == pcOldGroup) {
  1365. X            register struct group *grpTemp;
  1366. X
  1367. X            pCLCheck->gid = statb_dir.st_gid;
  1368. X            grpTemp = getgrgid(statb_dir.st_gid);
  1369. X            if ((struct group *)0 != grpTemp) {
  1370. X                (void)strcpy(pCLCheck->acgroup, grpTemp->gr_name);
  1371. X            } else {
  1372. X                (void)sprintf(pCLCheck->acgroup, "%d", statb_dir.st_gid);
  1373. X            }
  1374. X        } else {
  1375. X            pCLCheck->gid = grpOldDef->gr_gid;
  1376. X            (void)strcpy(pCLCheck->acgroup, grpOldDef->gr_name);
  1377. X        }
  1378. X
  1379. X        pCLCheck->mtype = S_IFDIR;
  1380. X        if ((char *)0 == pcOldMode) {
  1381. X            pCLCheck->mmust = PERM_BITS(statb_dir.st_mode);
  1382. X            pCLCheck->moptional = S_ISGID;
  1383. X        } else {
  1384. X            pCLCheck->mmust = mOldMust;
  1385. X            pCLCheck->moptional = mOldQuest;
  1386. X        }
  1387. X        pCLCheck->chstrip = CF_NONE;
  1388. X        (void)NodeType(pCLCheck->mtype, pCLCheck->acmode);
  1389. X        ModetoStr(pCLCheck->acmode+1, pCLCheck->mmust, pCLCheck->moptional);
  1390. X
  1391. X        if (-1 == stat(acCurOld, & statb_old)) {
  1392. X            if (ENOENT != errno)
  1393. X                (void)fprintf(stderr, "%s: stat: %s: %s\n", progname, acCurOld, strerror(errno));
  1394. X            continue;
  1395. X        }
  1396. X        (void)DoCk(acCurOld, &statb_old);
  1397. X
  1398. X        /* goto the directory and seach for poor backups
  1399. X         */
  1400. X        if (-1 == chdir(acCurOld)) {
  1401. X            (void)fprintf(stderr, "%s: chdir: %s: %s\n", progname, acCurOld, strerror(errno));
  1402. X            continue;
  1403. X        }
  1404. X        if ((DIR *)0 == (pDI = opendir("."))) {
  1405. X            (void)fprintf(stderr, "%s: opendir: %s/%s/.: %s\n", progname, ppcDirs[i], acOld, strerror(errno));
  1406. X            continue;
  1407. X        }
  1408. X        while ((struct direct *)0 != (pDE = readdir(pDI))) {
  1409. X            if ('.' == pDE->d_name[0] && ('\000' == pDE->d_name[1] ||
  1410. X               ('.' == pDE->d_name[1] && '\000' == pDE->d_name[2])))
  1411. X                continue;
  1412. X            if (-1 == LSTAT(pDE->d_name, &statb_backup)) {
  1413. X                (void)fprintf(stderr, "%s: stat: %s/%s/%s: %s\n", progname, ppcDirs[i], acOld, pDE->d_name, strerror(errno));
  1414. X                continue;
  1415. X            }
  1416. X            if (S_IFREG != (statb_backup.st_mode & S_IFMT)) {
  1417. X                (void)fprintf(fpOut, "%s: `%s/%s/%s\' not a plain file\n", progname, ppcDirs[i], acOld, pDE->d_name);
  1418. X                continue;
  1419. X            }
  1420. X            if (1 != statb_backup.st_nlink) {
  1421. X                FixLinks(ppcDirs[i], acOld, pDE->d_name, & statb_backup);
  1422. X            }
  1423. X            fChMode = 0;
  1424. X            if (0 != (statb_backup.st_mode & S_ISUID)) {
  1425. X                (void)fprintf(fpOut, "%s: `%s/%s/%s\' has setuid bit\n", progname, ppcDirs[i], acOld, pDE->d_name);
  1426. X                fChMode = 1;
  1427. X            }
  1428. X            if (0 != (statb_backup.st_mode & S_ISGID)) {
  1429. X                (void)fprintf(fpOut, "%s: `%s/%s/%s\' has setgid bit\n", progname, ppcDirs[i], acOld, pDE->d_name);
  1430. X                fChMode = 1;
  1431. X            }
  1432. X            if (0 != (statb_backup.st_mode & S_ISVTX)) {
  1433. X                (void)fprintf(fpOut, "%s: `%s/%s/%s\' has sticky bit\n", progname, ppcDirs[i], acOld, pDE->d_name);
  1434. X                fChMode = 1;
  1435. X            }
  1436. X            if (fInteract && fChMode) {
  1437. #if BROKEN_CHMOD
  1438. X                /* We know this is a file and files allow
  1439. X                 * us to drop the set?id bit with an octal
  1440. X                 * change, but they (Sun) might break this...
  1441. X                 */
  1442. X                SunBotch(acMode, PERM_BITS(statb_backup.st_mode), PERM_RWX(statb_backup.st_mode));
  1443. #else
  1444. X                (void)sprintf(acMode, "%04o", PERM_RWX(statb_backup.st_mode));
  1445. #endif
  1446. X                if (QExec(BINCHMOD, acMode, pDE->d_name, "special OLD file"))
  1447. X                    continue;
  1448. X            }
  1449. X        }
  1450. X        (void)closedir(pDI);
  1451. X    }
  1452. }
  1453. X
  1454. /*
  1455. X * if we are given an OLD dir, just run the OldCk on it            (ksb)
  1456. X */
  1457. int
  1458. FilterOld(iCount, ppcDirs, pCLCheck)
  1459. int iCount;
  1460. char **ppcDirs;
  1461. CHLIST *pCLCheck;        /* the checklist buffer DoCk uses    */
  1462. {
  1463. X    register char *pcTail;
  1464. X    auto int i, j, fCmp, k;
  1465. X    auto char **ppcOlds;
  1466. X
  1467. X    ppcOlds = (char **)calloc(iCount, sizeof(char *));
  1468. X    if ((char **)0 == ppcOlds) {
  1469. X        Die("calloc: no memory");
  1470. X    }
  1471. X    i = j = 0;
  1472. X    for (k = 0; k < iCount; ++k) {
  1473. X        ppcDirs[i] = ppcDirs[k];
  1474. X        if ((char *)0 == (pcTail = strrchr(ppcDirs[i], '/'))) {
  1475. X            fCmp = strcmp(ppcDirs[i], acOld);
  1476. X        } else {
  1477. X            fCmp = strcmp(pcTail+1, acOld);
  1478. X        }
  1479. X        if (0 != fCmp) {
  1480. X            ++i;
  1481. X            continue;
  1482. X        }
  1483. X        if ((char *)0 == pcTail) {
  1484. X            ppcOlds[j] = ".";
  1485. X        } else if (pcTail == ppcDirs[i]) {
  1486. X            ppcOlds[j] = "/";
  1487. X        } else {
  1488. X            *pcTail = '\000';
  1489. X            ppcOlds[j] = malloc(strlen(ppcDirs[i])+1);
  1490. X            if ((char *)0 == ppcOlds[j]) {
  1491. X                Die("malloc: no memory");
  1492. X            }
  1493. X            (void)strcpy(ppcOlds[j], ppcDirs[i]);
  1494. X            *pcTail = '/';
  1495. X        }
  1496. X        ++j;
  1497. X    }
  1498. X    if (0 != j) {
  1499. X        OldCk(j, ppcOlds, pCLCheck);
  1500. X    }
  1501. X    return i;
  1502. }
  1503. Purdue
  1504. chmod 0444 instck/instck.c ||
  1505. echo 'restore of instck/instck.c failed'
  1506. Wc_c="`wc -c < 'instck/instck.c'`"
  1507. test 34702 -eq "$Wc_c" ||
  1508.     echo 'instck/instck.c: original size 34702, current size' "$Wc_c"
  1509. fi
  1510. # ============= instck/gen.c ==============
  1511. if test -f 'instck/gen.c' -a X"$1" != X"-c"; then
  1512.     echo 'x - skipping instck/gen.c (File already exists)'
  1513. else
  1514. echo 'x - extracting instck/gen.c (Text)'
  1515. sed 's/^X//' << 'Purdue' > 'instck/gen.c' &&
  1516. /*
  1517. X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
  1518. X * 47907.  All rights reserved.
  1519. X *
  1520. X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
  1521. X *
  1522. X * This software is not subject to any license of the American Telephone
  1523. X * and Telegraph Company or the Regents of the University of California.
  1524. X *
  1525. X * Permission is granted to anyone to use this software for any purpose on
  1526. X * any computer system, and to alter it and redistribute it freely, subject
  1527. X * to the following restrictions:
  1528. X *
  1529. X * 1. Neither the authors nor Purdue University are responsible for any
  1530. X *    consequences of the use of this software.
  1531. X *
  1532. X * 2. The origin of this software must not be misrepresented, either by
  1533. X *    explicit claim or by omission.  Credit to the authors and Purdue
  1534. X *    University must appear in documentation and sources.
  1535. X *
  1536. X * 3. Altered versions must be plainly marked as such, and must not be
  1537. X *    misrepresented as being the original software.
  1538. X *
  1539. X * 4. This notice may not be removed or altered.
  1540. X */
  1541. X
  1542. /*
  1543. X * these routines generate a file which will tell instck(1L)        (ksb)
  1544. X * what modes and owners all the listed files should have.
  1545. X */
  1546. #if !defined(lint)
  1547. static char *rcsid =
  1548. X    "$Id: gen.c,v 7.6 90/11/28 13:08:08 ksb Exp $";
  1549. #endif    /* !lint */
  1550. X
  1551. #include <sys/param.h>
  1552. #include <sys/types.h>
  1553. #include <sys/stat.h>
  1554. #include <sys/file.h>
  1555. #include <sys/time.h>
  1556. #include <sys/dir.h>
  1557. X
  1558. #include "configure.h"
  1559. #include "install.h"
  1560. #include "main.h"
  1561. #include "syscalls.h"
  1562. #include "special.h"
  1563. #include "instck.h"
  1564. #include "gen.h"
  1565. #include "maxfreq.h"
  1566. #include "path.h"
  1567. #include "filedup.h"
  1568. X
  1569. #include <stdio.h>
  1570. #include <ctype.h>
  1571. #include <errno.h>
  1572. #include <pwd.h>
  1573. #include <grp.h>
  1574. X
  1575. #if STRINGS
  1576. #include <strings.h>
  1577. #else
  1578. #include <string.h>
  1579. #endif
  1580. X
  1581. extern char *calloc();
  1582. FILEDUPS FDLinks;
  1583. X
  1584. /*
  1585. X * copy the parent directory of pcFile to pcDir, which is a buffer    (ksb)
  1586. X * given by the user. returns the `tail part'
  1587. X */
  1588. static char *
  1589. getparent(pcFile, pcDir)
  1590. char *pcFile, *pcDir;
  1591. {
  1592. X    register char *pcTail;
  1593. X
  1594. X    if ((char *)0 == (pcTail = strrchr(pcFile, '/'))) {
  1595. X        if ((char *)0 != pcDir)
  1596. X            (void)strcpy(pcDir, ".");
  1597. X        return pcFile;
  1598. X    } else if (pcFile == pcTail) {
  1599. X        if ((char *)0 != pcDir)
  1600. X            (void)strcpy(pcDir, "/");
  1601. X        return pcFile+1;
  1602. X    }
  1603. X    *pcTail = '\000';
  1604. X    if ((char *)0 != pcDir)
  1605. X        (void)strcpy(pcDir, pcFile);
  1606. X    *pcTail = '/';
  1607. X    return pcTail+1;
  1608. }
  1609. X
  1610. static COMPONENT *pCMRoot;
  1611. static int fBeenHere = 0;
  1612. static struct passwd *pwdLast;
  1613. static struct group *grpLast;
  1614. static char acModeLast[sizeof("drwxrwxrwx")+1];
  1615. static dev_t devLast;
  1616. X
  1617. extern int stat(), lstat();
  1618. X
  1619. /*
  1620. X * do the nifty output                            (ksb)
  1621. X */
  1622. static int
  1623. DoGen(pcFile, pstThis)
  1624. char *pcFile;
  1625. struct stat *pstThis;
  1626. {
  1627. X    auto struct passwd *pwdThis;
  1628. X    auto struct group *grpThis;
  1629. X    auto char acModeThis[sizeof("drwxrwxrwx")+1];
  1630. X    static char acFormat[] = "%-15s %-7s %-7s ";
  1631. X    static char acLFormat[] = "%-23s %c%s\n";
  1632. X    static char acSCom[] = "\t#";
  1633. X    auto int fdFile, fBadLookUp;
  1634. X    auto int fCom;
  1635. X
  1636. X    (void)NodeType(pstThis->st_mode, acModeThis);
  1637. X    if ('l' == acModeThis[0]) {
  1638. X        auto char acLink[MAXPATHLEN+2];
  1639. X        register int i;
  1640. X        if (-1 == (i = readlink(pcFile, acLink, MAXPATHLEN))) {
  1641. X            fprintf(stderr, "%s: readlink: %s: %s\n", progname, pcFile, strerror(errno));
  1642. X            return 0;
  1643. X        }
  1644. X        acLink[i] = '\000';
  1645. X        fprintf(stdout, acLFormat, pcFile, '@', acLink);
  1646. X        return 0;
  1647. X    }
  1648. X    if (pstThis->st_nlink > 1 && fLinks) {
  1649. X        register char *pcLink;
  1650. X        pcLink = FDAdd(& FDLinks, pcFile, pstThis);
  1651. X        if (0 != strcmp(pcLink, pcFile)) {
  1652. X            fprintf(stdout, acLFormat, pcFile, ':', pcLink);
  1653. X            return 0;
  1654. X        }
  1655. X    }
  1656. X    fBadLookUp = 0;
  1657. X    pwdThis = getpwuid((int) pstThis->st_uid);
  1658. X    if ((struct passwd *)0 == pwdThis) {
  1659. X        fprintf(stderr, "%s: %s: getpwuid: %d: unknown uid\n", progname, pcFile, pstThis->st_uid);
  1660. X        fBadLookUp = 1;
  1661. X    }
  1662. X    grpThis = getgrgid((int) pstThis->st_gid);
  1663. X    if ((struct group *)0 == grpThis) {
  1664. X        fprintf(stderr, "%s: %s: getgrgid: %d: unknown gid\n", progname, pcFile, pstThis->st_gid);
  1665. X        fBadLookUp |= 2;
  1666. X    }
  1667. X    ModetoStr(acModeThis+1, (int)PERM_BITS(pstThis->st_mode), 00000);
  1668. X
  1669. X    /* make different devices show all again
  1670. X     */
  1671. X    if (acModeLast[0] != acModeThis[0] ||
  1672. X        (('b' == acModeLast[0] || 'c' == acModeLast[0]) &&
  1673. X        major(devLast) != major(pstThis->st_rdev))) {
  1674. X        fBeenHere = 0;
  1675. X    }
  1676. X    devLast = pstThis->st_rdev;
  1677. X
  1678. X    /* use the \" notation for multiple lines sometimes,
  1679. X     * looks, *lots* better
  1680. X     */
  1681. X    if (fBadLookUp) {
  1682. X        (void)fputc('#', stdout);
  1683. X    }
  1684. X    (void)printf("%-24s ", pcFile);
  1685. X    if (fBadLookUp) {
  1686. X        static char *apcBad[3] = {
  1687. X            "uid", "gid", "uid and gid"
  1688. X        };
  1689. X        fBeenHere = 0;
  1690. X        (void)printf(acFormat, acModeThis, ((struct passwd *)0 != pwdThis) ? pwdThis->pw_name : "*", ((struct group *)0 != grpThis) ? grpThis->gr_name : "*");
  1691. X        (void)printf("-\t# unknown %s\n", apcBad[fBadLookUp-1]);
  1692. X        return 0;
  1693. X    } else if (fBeenHere && !fVerbose) {
  1694. X        /* one of the most complicated C expressions I have ever coded
  1695. X         * keep dups in columns, keep last up to date
  1696. X         */
  1697. X        (void)printf(acFormat,
  1698. X            0 == strcmp(acModeThis, acModeLast) && 0 == (pstThis->st_mode & (S_ISVTX|S_ISUID|S_ISGID)) ? "\"" : ((void)strcpy(acModeLast, acModeThis), acModeThis),
  1699. X            pwdThis->pw_uid == pwdLast->pw_uid && 0 == (pstThis->st_mode & S_ISUID) ? "\"" : (free((char *)pwdLast), pwdLast = savepwent(pwdThis), pwdThis->pw_name),
  1700. X            grpThis->gr_gid == grpLast->gr_gid && 0 == (pstThis->st_mode & S_ISGID) ? "\"" : (free((char *)grpLast), grpLast = savegrent(grpThis), grpThis->gr_name)
  1701. X        );
  1702. X    } else {
  1703. X        (void)printf(acFormat, acModeThis, pwdThis->pw_name, grpThis->gr_name);
  1704. X        pwdLast = savepwent(pwdThis);
  1705. X        grpLast = savegrent(grpThis);
  1706. X        (void)strcpy(acModeLast, acModeThis);
  1707. X        fBeenHere = 1;
  1708. X    }
  1709. X
  1710. X    if ('-' != acModeThis[0]) {
  1711. X        (void)fputc('-', stdout);
  1712. X    } else if (0 > (fdFile = open(pcFile, 0, 0000))) {
  1713. X        if (errno != EACCES) {
  1714. X            (void)fprintf(stderr, "%s: open: %s: %s\n", progname, pcFile, strerror(errno));
  1715. X        }
  1716. X        (void)fputc('*', stdout);
  1717. X    } else {
  1718. X        register char *pcDot;
  1719. X        if ((char *)0 != (pcDot = strrchr(pcFile, '.')) && 'a' == pcDot[1] && '\000' == pcDot[2]) {
  1720. X            switch (IsRanlibbed(fdFile, pstThis)) {
  1721. X            case -1:    /* not a library    */
  1722. X                (void)fputc('n', stdout);
  1723. X                break;
  1724. X            case 0:        /* library, not ranlibbed */
  1725. X            case 1:        /* binary, ranlibbed */
  1726. X                (void)fputc('l', stdout);
  1727. X                break;
  1728. X            }
  1729. X        } else if (0 != (pstThis->st_mode & 0111)) {
  1730. X            switch (IsStripped(fdFile, pstThis)) {
  1731. X            case -1:    /* not a binary    */
  1732. X                (void)fputc('n', stdout);
  1733. X                break;
  1734. X            case 0:        /* binary, not stripped */
  1735. X                (void)fputc('?', stdout);
  1736. X                break;
  1737. X            case 1:        /* binary, stripped */
  1738. X                (void)fputc('s', stdout);
  1739. X                break;
  1740. X            }
  1741. X        } else {
  1742. X            (void)fputc('n', stdout);
  1743. X        }
  1744. X        (void)close(fdFile);
  1745. X    }
  1746. X
  1747. X    /* make crass comments about things we know a little about
  1748. X     *    mode 04100 is redundant
  1749. X     *    mode 02010 is redundant too
  1750. X     *    mode 00022 is dangerous
  1751. X     *    if (perm(group) == perm(other)) group should be default
  1752. X     *    never setgid default group
  1753. X     */
  1754. X    fCom = 0;
  1755. X    if (0 == (pstThis->st_mode & 0011) && 0 != (pstThis->st_mode & 0100) && 0 != (pstThis->st_mode & 04000)) {
  1756. X        if (!fCom)
  1757. X            (void)printf(acSCom);
  1758. X        (void)printf(" redundant setuid?");
  1759. X        ++fCom;
  1760. X    }
  1761. X    if (0 == (pstThis->st_mode & 0101) && 0 != (pstThis->st_mode & 0010) && 0 != (pstThis->st_mode & 02000)) {
  1762. X        if (!fCom)
  1763. X            (void)printf(acSCom);
  1764. X        (void)printf(" redundant setgid?");
  1765. X        ++fCom;
  1766. X    }
  1767. X    if (0 != (pstThis->st_mode & 0022)) {
  1768. X        if (!fCom)
  1769. X            (void)printf(acSCom);
  1770. X        (void)printf(" write bits?");
  1771. X        ++fCom;
  1772. X    }
  1773. X    if ((struct group *)0 != grpDef && pstThis->st_gid != grpDef->gr_gid && 0 == (pstThis->st_mode & S_ISGID) && ((pstThis->st_mode & 070) >> 3) == (pstThis->st_mode & 07)) {
  1774. X        if (!fCom)
  1775. X            (void)printf(acSCom);
  1776. X        printf(" group %s?", grpDef->gr_name);
  1777. X        ++fCom;
  1778. X    }
  1779. X    if ((struct group *)0 != grpDef && pstThis->st_gid == grpDef->gr_gid && 0 != (pstThis->st_mode & S_ISGID)) {
  1780. X        if (!fCom)
  1781. X            (void)printf(acSCom);
  1782. X        printf(" setgid %s?", grpDef->gr_name);
  1783. X        ++fCom;
  1784. X    }
  1785. X    /* someday we might do something with fCom here? -- ksb */
  1786. X    (void)fputc('\n', stdout);
  1787. X
  1788. X    return 0;
  1789. }
  1790. X
  1791. static MAXFREQ **ppMFRoot;
  1792. X
  1793. /*
  1794. X * copy an ME element
  1795. X * configure the MF routines here
  1796. X */
  1797. int
  1798. MECopy(pMEDest, pMESource)
  1799. X    ME_ELEMENT *pMEDest, *pMESource;
  1800. {
  1801. X    *pMEDest = *pMESource;
  1802. X    return 0;
  1803. }
  1804. X
  1805. /*
  1806. X * comparet two ME elements return 0 if they are equal; non-zero if they
  1807. X * are not
  1808. X */
  1809. int
  1810. MECompare(pME1, pME2)
  1811. X    ME_ELEMENT *pME1, *pME2;
  1812. {
  1813. X    return pME1->chtype - pME2->chtype ||
  1814. X        pME1->iuid - pME2->iuid ||
  1815. X        pME1->igid - pME2->igid ||
  1816. X        pME1->imode - pME2->imode;
  1817. }
  1818. X
  1819. /*
  1820. X * scan a directory (passwd each file within) for most common        (ksb)
  1821. X * { owner, group, mode, 'd'/'-' } tuple
  1822. X */
  1823. /*ARGSUSED*/
  1824. static int
  1825. DoStats(pcFile, pstThis)
  1826. char *pcFile;
  1827. struct stat *pstThis;
  1828. {
  1829. X    auto ME_ELEMENT METhis;
  1830. X
  1831. X    METhis.imode = PERM_BITS(pstThis->st_mode);
  1832. X    METhis.iuid = pstThis->st_uid;
  1833. X    METhis.igid = pstThis->st_gid;
  1834. X    (void)NodeType(pstThis->st_mode, & METhis.chtype);
  1835. X    if (METhis.chtype == '-') {
  1836. X        MFIncrement(ppMFRoot, & METhis);
  1837. X    }
  1838. X    return 0;
  1839. }
  1840. X
  1841. static ME_ELEMENT MESame;
  1842. X
  1843. /*
  1844. X * output files with a different `ME' for this directory        (ksb)
  1845. X * (also output if fLinks and st_nlink > 1)
  1846. X */
  1847. static int
  1848. DoDiffs(pcFile, pstThis)
  1849. char *pcFile;
  1850. struct stat *pstThis;
  1851. {
  1852. X    auto char ch;
  1853. X
  1854. X    (void)NodeType(pstThis->st_mode, &ch);
  1855. X    if (MESame.chtype == ch && MESame.iuid == pstThis->st_uid && MESame.igid == pstThis->st_gid && MESame.imode == PERM_BITS(pstThis->st_mode) && !(fLinks && 1 < pstThis->st_nlink)) {
  1856. X        return 0;
  1857. X    }
  1858. X    (void)DoGen(pcFile, pstThis);
  1859. X    return 0;
  1860. }
  1861. X
  1862. X
  1863. typedef struct PMnode {
  1864. X    struct passwd *s_pwd;
  1865. X    struct group *s_grp;
  1866. X    char s_acmode[20];
  1867. } PMODES;
  1868. X
  1869. /*
  1870. X * save the current dirs modes if we are doing an inherit on that prop    (ksb)
  1871. X * and take the new ones from the given file
  1872. X */
  1873. static void
  1874. PushModes(pST, pPM)
  1875. struct stat *pST;
  1876. PMODES *pPM;
  1877. {
  1878. X    if ((char *)0 == DEFOWNER || '\000' == DEFOWNER[0]) {
  1879. X        pPM->s_pwd = pwdDef;
  1880. X        pwdDef = getpwuid((int) pST->st_uid);
  1881. X        if ((struct passwd *)0 == pwdDef) {
  1882. X            fprintf(stderr, "%s: getpwuid: %d: unknown uid\n", progname, pST->st_uid);
  1883. X            pwdDef = pPM->s_pwd;
  1884. X            if ((struct passwd *)0 == pwdDef)
  1885. X                exit(1);
  1886. X        } else {
  1887. X            pwdDef = savepwent(pwdDef);
  1888. X        }
  1889. X    }
  1890. X    if ((char *)0 == DEFGROUP || '\000' == DEFGROUP[0]) {
  1891. X        pPM->s_grp = grpDef;
  1892. X        grpDef = getgrgid((int) pST->st_gid);
  1893. X        if ((struct group *)0 == grpDef) {
  1894. X            fprintf(stderr, "%s: getgrgid: %d: unknown gid\n", progname, pST->st_gid);
  1895. X            grpDef = pPM->s_grp;
  1896. X            if ((struct group *)0 == grpDef)
  1897. X                exit(1);
  1898. X        } else {
  1899. X            grpDef = savegrent(grpDef);
  1900. X        }
  1901. X    }
  1902. X    if ((char *)0 == pcMode) {
  1903. X        (void)strcpy(pPM->s_acmode, pcDefMode);
  1904. X        ModetoStr(pcDefMode+1, (int)PERM_BITS(pST->st_mode), 0);
  1905. X    }
  1906. }
  1907. X
  1908. /*
  1909. X * restore all the saved modes for this directory            (ksb)
  1910. X */
  1911. static void
  1912. PopModes(pPM)
  1913. PMODES *pPM;
  1914. {
  1915. X    if ((char *)0 == DEFOWNER || '\000' == DEFOWNER[0]) {
  1916. X        free((char *)pwdDef);
  1917. X        pwdDef = pPM->s_pwd;
  1918. X    }
  1919. X    if ((char *)0 == DEFGROUP || '\000' == DEFGROUP[0]) {
  1920. X        free((char *)grpDef);
  1921. X        grpDef = pPM->s_grp;
  1922. X    }
  1923. X    if ((char *)0 == pcMode) {
  1924. X        (void)strcpy(pcDefMode, pPM->s_acmode);
  1925. X    }
  1926. }
  1927. X
  1928. /*
  1929. X * generate a checklist for the given direcotires            (ksb)
  1930. X */
  1931. int
  1932. GenCk(argc, argv)
  1933. int argc;
  1934. char **argv;
  1935. {
  1936. X    register PATH_DATA *pPD;
  1937. X    register int i;
  1938. X    register char *pcFile;
  1939. X    auto struct passwd *pwdThis;
  1940. X    auto struct group *grpThis;
  1941. X    auto struct stat stThis, stAbove;
  1942. X    auto MAXFREQ **ppMFStats;
  1943. X    auto char acMode[20];
  1944. X    auto char acPat[MAXPATHLEN+3];
  1945. X    auto PMODES PMFile, PMDir;
  1946. X
  1947. X    ppMFStats = (MAXFREQ **)calloc(sizeof(MAXFREQ *), argc+1);
  1948. X    if ((MAXFREQ **)0 == ppMFStats) {
  1949. X        fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
  1950. X        exit(2);
  1951. X    }
  1952. X
  1953. X    FDInit(&FDLinks);
  1954. X
  1955. X    /* scan for plain files, collect stats on dirs
  1956. X     */
  1957. X    for (i = 0; i < argc && (char *)0 != (pcFile = argv[i]); ++i) {
  1958. X        pPD = AddPath(& pCMRoot, pcFile);
  1959. X        if (0 != pPD->fseen) {
  1960. X            continue;
  1961. X        }
  1962. X        pPD->fseen = 1;
  1963. X        if (-1 == (fLinks ? lstat : stat)(pcFile, &stThis)) {
  1964. X            fprintf(stderr, "%s: stat: %s %s\n", progname, pcFile, strerror(errno));
  1965. X            continue;
  1966. X        }
  1967. X        ppMFRoot = & ppMFStats[i];
  1968. X        (void)getparent(pcFile, acPat);
  1969. X        if (-1 == stat(acPat, &stAbove)) {
  1970. X            fprintf(stderr, "%s: stat: %s %s\n", progname, acPat, strerror(errno));
  1971. X            continue;
  1972. X        }
  1973. X        PushModes(&stAbove, & PMFile);
  1974. X        if (S_IFDIR == (stThis.st_mode & S_IFMT)) {
  1975. X            (void)DoGen(pcFile, & stThis);
  1976. X            PushModes(&stThis, & PMDir);
  1977. X            if (fDirs) {
  1978. X                FileMatch("*", pcFile, DoStats);
  1979. X            }
  1980. X            PopModes(& PMDir);
  1981. X        } else {
  1982. X            (void)DoGen(pcFile, &stThis);
  1983. X        }
  1984. X        PopModes(& PMFile);
  1985. X    }
  1986. X
  1987. X    /* scan for base rules
  1988. X     */
  1989. X    for (i = 0; i < argc && (char *)0 != (pcFile = argv[i]); ++i) {
  1990. X        if (-1 == stat(pcFile, &stThis)) {
  1991. X            fprintf(stderr, "%s: stat: %s %s\n", progname, pcFile, strerror(errno));
  1992. X            continue;
  1993. X        }
  1994. X        if (S_IFDIR != (stThis.st_mode & S_IFMT) || !fDirs || (MAXFREQ *)0 == ppMFStats[i]) {
  1995. X            continue;
  1996. X        }
  1997. X        MESame = ppMFStats[i]->ME;
  1998. X
  1999. X        PushModes(&stThis, & PMDir);
  2000. X        /* If the `*' pat for this dir would only match a few files
  2001. X         * just put those files in literally.
  2002. X         */
  2003. X        if (1 == ppMFStats[i]->icount || fLongList) {
  2004. X            FileMatch("*", pcFile, DoGen);
  2005. X            PopModes(& PMDir);
  2006. X            continue;
  2007. X        }
  2008. X        FileMatch("*", pcFile, DoDiffs);
  2009. X        PopModes(& PMDir);
  2010. X
  2011. X        pwdThis = getpwuid((int) ppMFStats[i]->ME.iuid);
  2012. X        if (0 == pwdThis) {
  2013. X            fprintf(stderr, "%s: %s: getpwuid: %d: unknown uid\n", progname, pcFile, ppMFStats[i]->ME.iuid);
  2014. X            continue;
  2015. X        }
  2016. X        grpThis = getgrgid((int) ppMFStats[i]->ME.igid);
  2017. X        if (0 == grpThis) {
  2018. X            fprintf(stderr, "%s: %s: getgrgid: %d: unknown gid\n", progname, pcFile, ppMFStats[i]->ME.igid);
  2019. X            continue;
  2020. X        }
  2021. X        acMode[0] = MESame.chtype;
  2022. X        ModetoStr(acMode+1, (int)PERM_BITS(ppMFStats[i]->ME.imode), 00000);
  2023. X        (void)strcpy(acPat, pcFile);
  2024. X        (void)strcat(acPat, "/*" + ('/' == pcFile[strlen(pcFile)-1]));
  2025. X        (void)printf("%-24s %-15s %-7s %-7s ?\n", acPat, acMode, pwdThis->pw_name, grpThis->gr_name);
  2026. X        /* we have to reset fBeenHere so we don't copy the
  2027. X         * glob modes down to the next line, because we would be
  2028. X         * comparing to the line *above* the glob line
  2029. X         */
  2030. X        fBeenHere = 0;
  2031. X    }
  2032. }
  2033. Purdue
  2034. chmod 0444 instck/gen.c ||
  2035. echo 'restore of instck/gen.c failed'
  2036. Wc_c="`wc -c < 'instck/gen.c'`"
  2037. test 13940 -eq "$Wc_c" ||
  2038.     echo 'instck/gen.c: original size 13940, current size' "$Wc_c"
  2039. fi
  2040. # ============= purge/README ==============
  2041. if test ! -d 'purge'; then
  2042.     echo 'x - creating directory purge'
  2043.     mkdir 'purge'
  2044. fi
  2045. if test -f 'purge/README' -a X"$1" != X"-c"; then
  2046.     echo 'x - skipping purge/README (File already exists)'
  2047. else
  2048. echo 'x - extracting purge/README (Text)'
  2049. sed 's/^X//' << 'Purdue' > 'purge/README' &&
  2050. # $Id: README,v 7.0 90/09/17 11:38:41 ksb Exp $
  2051. X
  2052. Purge is run my cron at night to remove unwanted (aged) backup files
  2053. from the system OLD dirs.
  2054. X
  2055. Here is a suggested crontab line:
  2056. X    0 2 * * 1    purge -v -unews -uuucp / >>/usr/adm/purge.log 2>/tmp/prg$$; [ -s /tmp/prg$$ ] && Mail -s "purge failed" root </tmp/prg$$
  2057. X
  2058. kayessbee
  2059. Purdue
  2060. chmod 0444 purge/README ||
  2061. echo 'restore of purge/README failed'
  2062. Wc_c="`wc -c < 'purge/README'`"
  2063. test 322 -eq "$Wc_c" ||
  2064.     echo 'purge/README: original size 322, current size' "$Wc_c"
  2065. fi
  2066. true || echo 'restore of install.d/file.c failed'
  2067. echo End of part 1, continue with part 2
  2068. exit 0
  2069.  
  2070. exit 0 # Just in case...
  2071.