home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume23 / afio / part02 < prev    next >
Encoding:
Text File  |  1991-10-16  |  46.6 KB  |  2,208 lines

  1. Newsgroups: comp.sources.misc
  2. From: uunet!sawmill!prslnk!buhrt (Jeff Buhrt)
  3. Subject:  v23i034:  afio - Manipulate CPIO-format archive and files, Part02/02
  4. Message-ID: <1991Sep29.033507.11169@sparky.imd.sterling.com>
  5. X-Md4-Signature: 43ea4487c023f6587a86da9c26326359
  6. Date: Sun, 29 Sep 1991 03:35:07 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: uunet!sawmill!prslnk!buhrt (Jeff Buhrt)
  10. Posting-number: Volume 23, Issue 34
  11. Archive-name: afio/part02
  12. Environment: UNIX
  13.  
  14. #!/bin/sh
  15. # do not concatenate these parts, unpack them in order with /bin/sh
  16. # file afio.c continued
  17. #
  18. if test ! -r _shar_seq_.tmp; then
  19.     echo 'Please unpack part 1 first!'
  20.     exit 1
  21. fi
  22. (read Scheck
  23.  if test "$Scheck" != 2; then
  24.     echo Please unpack part "$Scheck" next!
  25.     exit 1
  26.  else
  27.     exit 0
  28.  fi
  29. ) < _shar_seq_.tmp || exit 1
  30. if test ! -f _shar_wnt_.tmp; then
  31.     echo 'x - still skipping afio.c'
  32. else
  33. echo 'x - continuing file afio.c'
  34. sed 's/^X//' << 'SHAR_EOF' >> 'afio.c' &&
  35. X            else
  36. X                *abase = linkp->l_forw;
  37. X            free((char *) linkp);
  38. X        } else if (linkp->l_ino == asb->sb_ino
  39. X            && linkp->l_dev == asb->sb_dev) {
  40. X            --linkp->l_nlink;
  41. X            return (linkp);
  42. X        } else
  43. X            linknext = linkp->l_forw;
  44. X    return (NULL);
  45. }
  46. X
  47. X
  48. /*
  49. X * linkleft()
  50. X *
  51. X * Complain about files with unseen links.
  52. X */
  53. STATIC void
  54. linkleft()
  55. {
  56. X    reg Link    *lp;
  57. X    reg Link    **base;
  58. X
  59. X    for (base = linkbase; base < linkbase + nel(linkbase); ++base)
  60. X        for (lp = *base; lp; lp = lp->l_forw)
  61. X            if (lp->l_nlink)
  62. X                VOID warn(lp->l_path->p_name, "Unseen link(s)");
  63. }
  64. X
  65. /*
  66. X * linkto()
  67. X *
  68. X * Remember a file with outstanding links. Returns a
  69. X * pointer to the associated link structure, or NULL
  70. X * when linking is not possible.
  71. X */
  72. STATIC Link *
  73. linkto(name, asb)
  74. char        *name;
  75. reg Stat    *asb;
  76. {
  77. X    reg Link    *linkp;
  78. X    reg Path    *path;
  79. X    reg Link    **abase;
  80. X
  81. X    if (((asb->sb_mode & S_IFMT) == S_IFDIR)
  82. X        || ((linkp = (Link *) memget(sizeof(Link))) == NULL)
  83. X        || ((path = (Path *) memget(sizeof(Path))) == NULL)
  84. X        || ((path->p_name = memstr(name)) == NULL))
  85. X        return (NULL);
  86. X    linkp->l_dev = asb->sb_dev;
  87. X    linkp->l_ino = asb->sb_ino;
  88. X    linkp->l_nlink = asb->sb_nlink - 1;
  89. X    linkp->l_size = asb->sb_size;
  90. X    linkp->l_path = path;
  91. X    path->p_forw = NULL;
  92. X    path->p_back = path;
  93. X    if (linkp->l_forw = *(abase = linkhash(asb->sb_ino)))
  94. X        linkp->l_forw->l_back = linkp;
  95. X    linkp->l_back = NULL;
  96. X    return (*abase = linkp);
  97. }
  98. X
  99. #ifndef    MEMCPY
  100. X
  101. /*
  102. X * memcpy()
  103. X *
  104. X * A simple block move.
  105. X */
  106. STATIC char    *
  107. memcpy(to, from, len)
  108. reg char    *to;
  109. reg char    *from;
  110. uint        len;
  111. {
  112. X    reg char    *toend;
  113. X
  114. X    for (toend = to + len; to < toend; *to++ = *from++)
  115. X        ;
  116. X    return(to);
  117. }
  118. X
  119. #endif    /* MEMCPY */
  120. X
  121. /*
  122. X * memget()
  123. X *
  124. X * Allocate memory.
  125. X */
  126. STATIC char *
  127. memget(len)
  128. uint        len;
  129. {
  130. X    reg char    *mem;
  131. X    static short    outofmem;
  132. X
  133. X    if ((mem = malloc(len)) == NULL && !outofmem)
  134. X        outofmem = warn("memget()", "Out of memory");
  135. X    return (mem);
  136. }
  137. X
  138. /*
  139. X * memstr()
  140. X *
  141. X * Duplicate a string into dynamic memory.
  142. X */
  143. STATIC char *
  144. memstr(str)
  145. reg char    *str;
  146. {
  147. X    reg char    *mem;
  148. X
  149. X    if (mem = memget((uint) strlen(str) + 1))
  150. X        VOID strcpy(mem, str);
  151. X    return (mem);
  152. }
  153. X
  154. #ifndef    MKDIR
  155. X
  156. /*
  157. X * mkdir()
  158. X *
  159. X * Make a directory via "/bin/mkdir". Sets errno to a
  160. X * questionably sane value upon failure.
  161. X */
  162. STATIC int
  163. mkdir(name, mode)
  164. reg char    *name;
  165. reg ushort    mode;
  166. {
  167. X    reg int        pid;
  168. X
  169. X    if ((pid = xfork("mkdir()", DIE)) == 0) {
  170. X        VOID close(fileno(stdin));
  171. X        VOID close(fileno(stdout));
  172. X        VOID close(fileno(stderr));
  173. X        VOID open("/dev/null", O_RDWR);
  174. X        VOID dup(fileno(stdin));
  175. X        VOID dup(fileno(stdin));
  176. X        VOID umask(~mode);
  177. X        VOID execl("/bin/mkdir", "mkdir", name, (char *) NULL);
  178. X        exit(1);
  179. X    }
  180. X    if (xwait(pid, "mkdir()", TRUE) == 0)
  181. X        return (0);
  182. X    errno = EACCES;
  183. X    return (-1);
  184. }
  185. X
  186. #endif    /* MKDIR */
  187. X
  188. /*
  189. X * nameadd()
  190. X *
  191. X * Add a name to the pattern list.
  192. X */
  193. STATIC void
  194. nameadd(name, not)
  195. reg char    *name;
  196. int        not;
  197. {
  198. X    reg Pattern    *px;
  199. X
  200. X    px = (Pattern *) memget(sizeof(Pattern));
  201. X    px->p_forw = pattern;
  202. X    px->p_str = name;
  203. X    px->p_len = strlen(name);
  204. X    px->p_not = not;
  205. X    pattern = px;
  206. }
  207. X
  208. /*
  209. X * namecmp()
  210. X *
  211. X * Compare a pathname with the pattern list. Returns 0 for
  212. X * a match, -1 otherwise.
  213. X */
  214. STATIC int
  215. namecmp(name)
  216. reg char    *name;
  217. {
  218. X    reg Pattern    *px;
  219. X    reg int        positive;
  220. X    reg int        match;
  221. X    int    x;
  222. X    int    wild = 0;
  223. X    int    comp;
  224. X
  225. /* FIXME -positive */
  226. X    positive = match = 0;
  227. X    if (pattern == NULL) return(0);    /* Ok if nothing spec'd */
  228. X    for (px = pattern; px; px = px->p_forw) {
  229. X        if (!px->p_not)
  230. X            ++positive;
  231. X        x = px->p_len;
  232. X        if (px->p_str[px->p_len - 1] == '*') {
  233. X            x--;        /* If wild, back up one */
  234. X            wild++;
  235. X        }
  236. X        comp = strncmp(name, px->p_str, x);
  237. X        if (px->p_not) {
  238. X            if (wild == 0)    {    /* If not wild */
  239. X                if ((name[x] != '\0') || (comp != 0))
  240. X                    ++match;
  241. X                else 
  242. X                    return(-1);    /* OUT NOW */
  243. X            } else
  244. X                if (comp != 0)
  245. X                    ++match;
  246. X                else
  247. X                    return(-1);    /* OUT NOW */
  248. X        } else {
  249. X            if (wild == 0) {    /* If not wild */
  250. X                if ((name[x] == '\0') && (comp == 0))
  251. X                    ++match;
  252. X            } else
  253. X                if (comp == 0)
  254. X                    ++match;
  255. X        }
  256. X    }
  257. X    if (match > 0) 
  258. X        return(0);
  259. X    return(-1);
  260. }
  261. X
  262. /*
  263. X * nameopt()
  264. X *
  265. X * Optimize a pathname. Confused by "<symlink>/.." twistiness.
  266. X * Returns the number of final pathname elements (zero for "/"
  267. X * or ".") or -1 if unsuccessful.
  268. X */
  269. STATIC int
  270. nameopt(begin)
  271. char    *begin;
  272. {
  273. X    reg char    *name;
  274. X    reg char    *item;
  275. X    reg int        idx;
  276. X    int        absolute;
  277. X    auto char    *element[PATHELEM];
  278. X
  279. X    absolute = (*(name = begin) == '/');
  280. X    idx = 0;
  281. X    for (;;) {
  282. X        if (idx == PATHELEM)
  283. X            return (warn(begin, "Too many elements"));
  284. X        while (*name == '/')
  285. X            ++name;
  286. X        if (*name == '\0')
  287. X            break;
  288. X        element[idx] = item = name;
  289. X        while (*name && *name != '/')
  290. X            ++name;
  291. X        if (*name)
  292. X            *name++ = '\0';
  293. X        if (strcmp(item, "..") == 0)
  294. X            if (idx == 0)
  295. X                if (absolute)
  296. X                    ;
  297. X                else
  298. X                    ++idx;
  299. X            else if (strcmp(element[idx - 1], "..") == 0)
  300. X                ++idx;
  301. X            else
  302. X                --idx;
  303. X        else if (strcmp(item, ".") != 0)
  304. X            ++idx;
  305. X    }
  306. X    if (idx == 0)
  307. X        element[idx++] = absolute ? "" : ".";
  308. X    element[idx] = NULL;
  309. X    name = begin;
  310. X    if (absolute)
  311. X        *name++ = '/';
  312. X    for (idx = 0; item = element[idx]; ++idx, *name++ = '/')
  313. X        while (*item)
  314. X            *name++ = *item++;
  315. X    *--name = '\0';
  316. X    return (idx);
  317. }
  318. X
  319. /*
  320. X * next()
  321. X *
  322. X * Advance to the next archive volume.
  323. X */
  324. STATIC void
  325. next(mode, why)
  326. reg int        mode;
  327. reg char    *why;
  328. {
  329. X    reg time_t    began;
  330. X    auto char    msg[200];
  331. X    auto char    answer[20];
  332. X
  333. X    began = time((time_t *) NULL);
  334. X    nextclos();
  335. X    VOID warnarch(why, (off_t) 0);
  336. X    if (arfd == STDIN || arfd == STDOUT)
  337. X        goodbye(1);
  338. X    ++arvolume;    /* change disk # here */
  339. X    VOID sprintf(msg, "\
  340. %s: Ready for disk %u on \"%s\" (remove the disk when the light goes out)\n\
  341. %s: Type \"go\" (or \"GO\") when ready to proceed %s: \07",
  342. X        myname, arvolume, arspec, myname,
  343. X        hidequit ? "" : "(or \"quit\" to abort )");
  344. X    for (;;) {
  345. X        nextask(msg, answer, sizeof(answer));
  346. X        if (strcmp(answer, "quit") == 0)
  347. X            fatal(arspec, "Aborted");
  348. X        if ((strcmp(answer, "go") == 0) || 
  349. X            (strcmp(answer, "GO") == 0))
  350. X        {
  351. X            /* only open the disk now if we it it right now */
  352. X            if (!Fflag || (mode == O_RDONLY))
  353. X            {    if (nextopen(mode) == 0)
  354. X                    break;
  355. X            }
  356. X            else
  357. X                break;
  358. X        }
  359. X    }
  360. X    VOID warnarch("Continuing", (off_t) 0);
  361. X    timewait += time((time_t *) NULL) - began;
  362. }
  363. X
  364. /*
  365. X * nextask()
  366. X *
  367. X * Ask a question and get a response. Ignores spaces and tabs.
  368. X */
  369. STATIC void
  370. nextask(msg, answer, limit)
  371. reg char    *msg;
  372. reg char    *answer;
  373. reg int        limit;
  374. {
  375. X    reg int        idx;
  376. X    reg int        got;
  377. X    auto char    c;
  378. X
  379. X    if (ttyf < 0)
  380. X        fatal(TTY, "Unavailable");
  381. X    VOID write(ttyf, msg, (uint) strlen(msg));
  382. X    idx = 0;
  383. X    while ((got = read(ttyf, &c, 1)) == 1)
  384. X        if (c == '\04' || c == '\n')
  385. X            break;
  386. X        else if (c == ' ' || c == '\t')
  387. X            continue;
  388. X        else if (idx < limit - 1)
  389. X            answer[idx++] = c;
  390. X    if (got < 0)
  391. X        fatal(TTY, syserr());
  392. X    answer[idx] = '\0';
  393. }
  394. X
  395. /*
  396. X * nextclos()
  397. X *
  398. X * Close an archive.
  399. X */
  400. STATIC void
  401. nextclos()
  402. {
  403. X    if (arfd != STDIN && arfd != STDOUT)
  404. X        VOID close(arfd);
  405. X    areof = 0;
  406. X    if (arname && *arname == '!')
  407. X        pipewait();
  408. }
  409. X
  410. /*
  411. X * nextopen()
  412. X *
  413. X * Open an archive. Returns 0 if successful, -1 otherwise.
  414. X */
  415. STATIC int
  416. nextopen(mode)
  417. int        mode;
  418. {
  419. X    if (*arname == '!')
  420. X        arfd = pipeopen(mode);
  421. X    else if (strcmp(arname, "-") == 0)
  422. X        arfd = mode ? STDOUT : STDIN;
  423. X    else {
  424. #ifdef    CTC3B2
  425. X        if (Cflag) {
  426. X            reg int        oops;
  427. X            reg int        fd;
  428. X
  429. X            oops = ((fd = open(arname, O_RDWR | O_CTSPECIAL)) < 0
  430. X                || ioctl(fd, STREAMON) < 0);
  431. X            VOID close(fd);
  432. X            if (oops)
  433. X                return (warnarch(syserr(), (off_t) 0));
  434. X        }
  435. #endif    /* CTC3B2 */
  436. X        arfd = mode ? creat(arname, 0666 & ~mask) : open(arname, mode);
  437. X    }
  438. X    if (arfd < 0)
  439. X        return (warnarch(syserr(), (off_t) 0));
  440. X    arleft = aruntil;
  441. X    return (0);
  442. }
  443. X
  444. /*
  445. X * openin()
  446. X *
  447. X * Open the next input file. Returns a file descriptor, 0 if no data
  448. X * exists, or -1 at EOF. This kludge works because standard input is
  449. X * in use, preventing open() from returning zero.
  450. X */
  451. STATIC int
  452. openin(name, asb)
  453. char        *name;
  454. reg Stat    *asb;
  455. {
  456. X    int        fd;
  457. X    auto char    local[PATHSIZE];
  458. X
  459. X    for (;;) {
  460. X        if (lineget(stdin, name) < 0)
  461. X            return (-1);
  462. X        if (nameopt(name) < 0)
  463. X            continue;
  464. X        if (!gflag)
  465. X            VOID strcpy(local, name);
  466. X        else if (dirchg(name, local) < 0)
  467. X            continue;
  468. X        if ((hflag ? STAT(local, asb) : LSTAT(local, asb)) < 0) {
  469. X            VOID warn(name, syserr());
  470. X            continue;
  471. X        }
  472. X        switch (asb->sb_mode & S_IFMT) {
  473. X        case S_IFDIR:
  474. X            asb->sb_nlink = 1;
  475. X            asb->sb_size = 0;
  476. X            return (0);
  477. #ifdef    S_IFLNK
  478. X        case S_IFLNK:
  479. X            if ((asb->sb_size = readlink(local,
  480. X                asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
  481. X                VOID warn(name, syserr());
  482. X                continue;
  483. X            }
  484. X            asb->sb_link[asb->sb_size] = '\0';
  485. X            return (0);
  486. #endif    /* S_IFLNK */
  487. X        case S_IFREG:
  488. X            if (asb->sb_size == 0)
  489. X                return (0);
  490. X            if ((fd = open(local, O_RDONLY)) >= 0)
  491. X            {    if (Zflag)
  492. X                    compressfile(&fd, name, asb);
  493. X
  494. X                return (fd);
  495. X            }
  496. X            VOID warn(name, syserr());
  497. X            break;
  498. X        default:
  499. X            asb->sb_size = 0;
  500. X            return (0);
  501. X        }
  502. X    }
  503. }
  504. X
  505. /*
  506. X * openotty()
  507. X *
  508. X * Open an output file. Returns the output file descriptor,
  509. X * 0 if no data is required or -1 if unsuccessful. Note that
  510. X * UNIX open() will never return 0 because the standard input
  511. X * is in use.
  512. X */
  513. STATIC int
  514. openotty(name, asb, linkp, ispass, dozflag)
  515. char        *name;
  516. reg Stat    *asb;
  517. Link        *linkp;
  518. reg int        ispass;
  519. int        dozflag;
  520. {
  521. X    reg int        exists;
  522. X    reg int        fd;
  523. X    reg ushort    perm;
  524. X    ushort        operm;
  525. X    ushort        ouid;
  526. X    ushort        ogid;
  527. X    Path        *path;
  528. X    auto Stat    osb;
  529. #ifdef    S_IFLNK
  530. X    reg int        ssize;
  531. X    auto char    sname[PATHSIZE];
  532. #endif    /* S_IFLNK */
  533. X    char        *namedot;
  534. X    auto int    pfd[2];
  535. X    int        comppid;
  536. X
  537. X    *uncompto = '\0';
  538. X    /*
  539. X     * -iZ try to uncompress a compress'd regular file
  540. X     */
  541. X    if (dozflag && !linkp && ((asb->sb_mode & S_IFMT) == S_IFREG) &&
  542. X            ((namedot = strrchr(name, '.')) != NULL) &&
  543. X            (strcmp(namedot, ".Z") == 0))
  544. X    {    *namedot = '\0';
  545. X    }
  546. X    else
  547. X        namedot = NULL;    /* not uncompressing */
  548. X    if (exists = (LSTAT(name, &osb) == 0))
  549. X        if (ispass
  550. X            && osb.sb_ino == asb->sb_ino
  551. X            && osb.sb_dev == asb->sb_dev)
  552. X            return (warn(name, "Same file"));
  553. X        else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT))
  554. X            operm = osb.sb_mode & (xflag ? S_IPERM : S_IPOPN);
  555. X        else if (afremove(name, &osb) < 0)
  556. X            return (warn(name, syserr()));
  557. X        else
  558. X            exists = 0;
  559. X    if (linkp) {
  560. X        if (exists)
  561. X            if (asb->sb_ino == osb.sb_ino
  562. X                && asb->sb_dev == osb.sb_dev)
  563. X                return (0);
  564. X            else if (unlink(name) < 0)
  565. X                return (warn(name, syserr()));
  566. X            else
  567. X                exists = 0;
  568. X        for (path = linkp->l_path; path; path = path->p_forw)
  569. X            if (link(path->p_name, name) == 0
  570. X              || (errno == ENOENT
  571. X                && dirneed(name) == 0
  572. X                && link(path->p_name, name) == 0))
  573. X                return (0);
  574. X            else if (errno != EXDEV)
  575. X                return (warn(name, syserr()));
  576. X        VOID warn(name, "Link broken");
  577. X        linkalso(linkp, name);
  578. X    }
  579. X    perm = asb->sb_mode & (xflag ? S_IPERM : S_IPOPN);
  580. X    if (exists){
  581. X        ouid = osb.sb_uid;
  582. X        ogid = osb.sb_gid;
  583. X    }
  584. X    switch (asb->sb_mode & S_IFMT) {
  585. X    case S_IFBLK:
  586. X    case S_IFCHR:
  587. X        fd = 0;
  588. X        if (exists)
  589. X            if (asb->sb_rdev == osb.sb_rdev)
  590. X                if (perm != operm && chmod(name, perm) < 0)
  591. X                    return (warn(name, syserr()));
  592. X                else
  593. X                    break;
  594. X            else if (afremove(name, &osb) < 0)
  595. X                return (warn(name, syserr()));
  596. X            else
  597. X                exists = 0;
  598. X        if (mknod(name, asb->sb_mode, asb->sb_rdev) < 0
  599. X          && (errno != ENOENT
  600. X            || dirneed(name) < 0
  601. X            || mknod(name, asb->sb_mode, asb->sb_rdev) < 0))
  602. X            return (warn(name, syserr()));
  603. X        break;
  604. X    case S_IFDIR:
  605. X        if (exists)
  606. X            if (perm != operm && chmod(name, perm) < 0)
  607. X                return (warn(name, syserr()));
  608. X            else if (xflag && (asb->sb_uid != ouid || asb->sb_gid != ogid) &&
  609. X                chown(name, asb->sb_uid, asb->sb_gid) < 0)
  610. X                return (warn(name, syserr()));
  611. X            else
  612. X                ;
  613. X        else if (dirneed(name) < 0 || dirmake(name, asb) < 0)
  614. X            return (warn(name, syserr()));
  615. X        return (0);
  616. #ifdef    S_IFIFO
  617. X    case S_IFIFO:
  618. X        fd = 0;
  619. X        if (exists)
  620. X            if (perm != operm && chmod(name, perm) < 0)
  621. X                return (warn(name, syserr()));
  622. X            else
  623. X                ;
  624. X        else if (mknod(name, asb->sb_mode, (dev_t) 0) < 0
  625. X          && (errno != ENOENT
  626. X            || dirneed(name) < 0
  627. X            || mknod(name, asb->sb_mode, (dev_t) 0) < 0))
  628. X            return (warn(name, syserr()));
  629. X        break;
  630. #endif    /* S_IFIFO */
  631. #ifdef    S_IFLNK
  632. X    case S_IFLNK:
  633. X        if (exists)
  634. X            if ((ssize = readlink(name, sname, sizeof(sname))) < 0)
  635. X                return (warn(name, syserr()));
  636. X            else if (strncmp(sname, asb->sb_link, ssize) == 0)
  637. X                return (0);
  638. X            else if (afremove(name, &osb) < 0)
  639. X                return (warn(name, syserr()));
  640. X            else
  641. X                exists = 0;
  642. X        if (symlink(asb->sb_link, name) < 0
  643. X          && (errno != ENOENT
  644. X            || dirneed(name) < 0
  645. X            || symlink(asb->sb_link, name) < 0))
  646. X            return (warn(name, syserr()));
  647. X        return (0);    /* Can't chown()/chmod() a symbolic link */
  648. #endif    /* S_IFLNK */
  649. X    case S_IFREG:
  650. X        if (exists)
  651. X            if (nflag && osb.sb_mtime > asb->sb_mtime)
  652. X                return (warn(name, "Newer file exists"));
  653. X            else if (unlink(name) < 0)
  654. X                return (warn(name, syserr()));
  655. X            else
  656. X                exists = 0;
  657. X        if ((fd = creat(name, perm)) < 0
  658. X          && (errno != ENOENT
  659. X            || dirneed(name) < 0
  660. X            || (fd = creat(name, perm)) < 0))
  661. X            return (warn(name, syserr()));
  662. X        if (dozflag && !linkp && namedot)
  663. X        {
  664. X            if (pipe(pfd) >= 0)
  665. X            {    if ((comppid = xfork("openotty(in), compressing", NODIE)) == 0)
  666. X            {    VOID close(pfd[1]);    /* child */
  667. X                VOID close(fileno(stdin));
  668. X                VOID dup(pfd[0]);
  669. X                VOID close(pfd[0]);
  670. X
  671. X                VOID close(fileno(stdout));
  672. X                if (dup(fd) < 0)
  673. X                    exit(1);
  674. X                execlp("uncompress", "uncompress", "-c", 0);
  675. X                fprintf(stderr, "Could not uncompress, errno %d\n", errno);
  676. X                exit(1);
  677. X            }
  678. X            else    /* life seems ok */
  679. X            if (comppid > 0)
  680. X            {    close(fd);
  681. X                fd = pfd[1];
  682. X                uncompressrun = comppid;
  683. X                strcpy(uncompto, name);
  684. X                *namedot = '.';
  685. X                break;
  686. X            }
  687. X            }
  688. X            /* we failed try again, not uncompressing the file */
  689. X            unlink(name);
  690. X            *namedot = '.';
  691. X            return(openotty(name, asb, linkp, ispass, FALSE));
  692. X        }
  693. X            
  694. X        break;
  695. X    default:
  696. X        return (warn(name, "Unknown filetype"));
  697. X    }
  698. X    if (xflag
  699. X      && (!exists
  700. X        || asb->sb_uid != osb.sb_uid
  701. X        || asb->sb_gid != osb.sb_gid))
  702. X        VOID chown(name,
  703. X            uid == 0 ? ush(asb->sb_uid) : uid,
  704. X            ush(asb->sb_gid));
  705. X    if (linkp == NULL && asb->sb_nlink > 1)
  706. X        VOID linkto(name, asb);
  707. X    return (fd);
  708. }
  709. X
  710. /*
  711. X * openqtty()
  712. X *
  713. X * Open the terminal for interactive queries (sigh). Assumes that
  714. X * background processes ignore interrupts and that the open() or
  715. X * the isatty() will fail for processes which are not attached to
  716. X * terminals. Returns a file descriptor (-1 if unsuccessful).
  717. X */
  718. int
  719. openqtty()
  720. {
  721. X    reg VOIDFN    (*intr)();
  722. X    int    fd;
  723. X
  724. X    fd = -1;
  725. X    if (!Fflag)
  726. X    {
  727. X        if ((intr = signal(SIGINT, SIG_IGN)) == SIG_IGN)
  728. X            return(fd);
  729. X        VOID signal(SIGINT, intr);
  730. X    }
  731. X
  732. X    if ((fd = open(TTY, O_RDWR)) < 0)
  733. X    {    VOID warn(TTY, syserr());
  734. X    }
  735. X    else
  736. X    if (!isatty(fd))
  737. X        VOID warn(TTY, "Is not a tty");
  738. X    return(fd);
  739. }
  740. X
  741. /*
  742. X * options()
  743. X *
  744. X * Decode most reasonable forms of UNIX option syntax. Takes main()-
  745. X * style argument indices (argc/argv) and a string of valid option
  746. X * letters. Letters denoting options with arguments must be followed
  747. X * by colons. With valid options, returns the option letter and points
  748. X * "optarg" at the associated argument (if any). Returns '?' for bad
  749. X * options and missing arguments. Returns zero when no options remain,
  750. X * leaving "optind" indexing the first remaining argument.
  751. X */
  752. STATIC int
  753. options(ac, av, proto)
  754. int        ac;
  755. register char    **av;
  756. char        *proto;
  757. {
  758. X    register int    c;
  759. X    register char    *idx;
  760. X    static int    optsub;
  761. X
  762. X    if (optind == 0) {
  763. X        optind = 1;
  764. X        optsub = 0;
  765. X    }
  766. X    optarg = NULL;
  767. X    if (optind >= ac)
  768. X        return (0);
  769. X    if (optsub == 0 && (av[optind][0] != '-' || av[optind][1] == '\0'))
  770. X        return (0);
  771. X    switch (c = av[optind][++optsub]) {
  772. X    case '\0':
  773. X        ++optind;
  774. X        optsub = 0;
  775. X        return (options(ac, av, proto));
  776. X    case '-':
  777. X        ++optind;
  778. X        optsub = 0;
  779. X        return (0);
  780. X    case ':':
  781. X        return ('?');
  782. X    }
  783. X    if ((idx = strchr(proto, c)) == NULL)
  784. X        return ('?');
  785. X    if (idx[1] != ':')
  786. X        return (c);
  787. X    optarg = &av[optind][++optsub];
  788. X    ++optind;
  789. X    optsub = 0;
  790. X    if (*optarg)
  791. X        return (c);
  792. X    if (optind >= ac)
  793. X        return ('?');
  794. X    optarg = av[optind++];
  795. X    return (c);
  796. }
  797. X
  798. /*
  799. X * optsize()
  800. X *
  801. X * Interpret a "size" argument. Recognizes suffices for blocks
  802. X * (512-byte), kilobytes and megabytes and blocksize. Returns
  803. X * the size in bytes.
  804. X */
  805. STATIC off_t
  806. optsize(str)
  807. char        *str;
  808. {
  809. X    reg char    *idx;
  810. X    reg off_t    number;
  811. X    reg off_t    result;
  812. X
  813. X    result = 0;
  814. X    idx = str;
  815. X    for (;;) {
  816. X        number = 0;
  817. X        while (*idx >= '0' && *idx <= '9')
  818. X            number = number * 10 + *idx++ - '0';
  819. X        switch (*idx++) {
  820. X        case 'b':
  821. X            result += number * 512;
  822. X            continue;
  823. X        case 'k':
  824. X            result += number * 1024;
  825. X            continue;
  826. X        case 'm':
  827. X            result += number * 1024L * 1024L;
  828. X            continue;
  829. X        case 'x':
  830. X            result += number * arbsize;
  831. X            continue;
  832. X        case '+':
  833. X            result += number;
  834. X            continue;
  835. X        case '\0':
  836. X            result += number;
  837. X            break;
  838. X        default:
  839. X            break;
  840. X        }
  841. X        break;
  842. X    }
  843. X    if (*--idx)
  844. X        fatal(str, "Unrecognizable value");
  845. X    return (result);
  846. }
  847. X
  848. /*
  849. X * out()
  850. X *
  851. X * Write an archive.
  852. X */
  853. STATIC VOIDFN
  854. out(av)
  855. char        **av;
  856. {
  857. X    reg int        fd;
  858. X    auto Stat    sb;
  859. X    auto char    name[PATHSIZE];
  860. X
  861. X    if (*av)
  862. X        fatal(*av, "Extraneous argument");
  863. X    while ((fd = openin(name, &sb)) >= 0) {
  864. X        if (!lflag && sb.sb_nlink > 1)
  865. X        {    if (linkfrom(&sb))
  866. X                sb.sb_size = 0;
  867. X            else
  868. X                VOID linkto(name, &sb);
  869. X        }
  870. X
  871. X        outhead(name, &sb);
  872. X        if (fd)
  873. X            VOID close(outdata(fd, name, sb.sb_size));
  874. X        if (vflag)
  875. X            VOID fprintf(stderr, "%s\n", name);
  876. X    }
  877. X    outeof(TRAILER, TRAILZ);
  878. }
  879. X
  880. /*
  881. X * outalloc()
  882. X *
  883. X * Allocate buffer space previously referenced by outavail().
  884. X */
  885. STATIC void
  886. outalloc(len)
  887. reg uint    len;
  888. {
  889. X    bufidx += len;
  890. X    total += len;
  891. }
  892. X
  893. /*
  894. X * outavail()
  895. X *
  896. X * Index buffer space for archive output. Stores a buffer pointer
  897. X * at a given location. Returns the number of bytes available.
  898. X */
  899. STATIC uint
  900. outavail(bufp)
  901. reg char    **bufp;
  902. {
  903. X    reg uint    have;
  904. X
  905. X    while ((have = bufend - bufidx) == 0)
  906. X        outflush(NOTDONE);
  907. X    *bufp = bufidx;
  908. X    return (have);
  909. }
  910. X
  911. /*
  912. X * outdata()
  913. X *
  914. X * Write archive data. Continues after file read errors, padding with
  915. X * null characters if neccessary. Always returns the given input file
  916. X * descriptor.
  917. X */
  918. STATIC int
  919. outdata(fd, name, size)
  920. int        fd;
  921. char        *name;
  922. reg off_t    size;
  923. {
  924. X    reg uint    chunk;
  925. X    reg int        got;
  926. X    reg int        oops;
  927. X    reg uint    avail;
  928. X    auto char    *buf;
  929. X
  930. X    oops = got = 0;
  931. X    while (size) {
  932. X        avail = outavail(&buf);
  933. X        size -= (chunk = size < avail ? (uint) size : avail);
  934. X        if (oops == 0 && (got = read(fd, buf, chunk)) < 0) {
  935. X            oops = warn(name, syserr());
  936. X            got = 0;
  937. X        }
  938. X        if (got < chunk) {
  939. X            if (oops == 0)
  940. X                oops = warn(name, "Early EOF");
  941. X            while (got < chunk)
  942. X                buf[got++] = '\0';
  943. X        }
  944. X        outalloc(chunk);
  945. X    }
  946. X    return (fd);
  947. }
  948. X
  949. /*
  950. X * outeof()
  951. X *
  952. X * Write an archive trailer.
  953. X */
  954. STATIC void
  955. outeof(name, namelen)
  956. char        *name;
  957. reg uint    namelen;
  958. {
  959. X    reg off_t    pad;
  960. X    auto char    header[M_STRLEN + H_STRLEN + 1];
  961. X
  962. X    if (pad = (total + M_STRLEN + H_STRLEN + namelen) % arpad)
  963. X        pad = arpad - pad;
  964. X    VOID strcpy(header, M_ASCII);
  965. X    VOID sprintf(header + M_STRLEN, H_PRINT, 0, 0,
  966. X        0, 0, 0, 1, 0, (time_t) 0, namelen, pad);
  967. X    outwrite(header, M_STRLEN + H_STRLEN);
  968. X    outwrite(name, namelen);
  969. X    outpad(pad);
  970. X    outflush(DONE);
  971. X    if (fflag)
  972. X        outwait();
  973. }
  974. X
  975. /*
  976. X * outflush()
  977. X *
  978. X * Flush the output buffer. Optionally fork()s to allow the
  979. X * parent to refill the buffer while the child waits for the
  980. X * write() to complete.
  981. X */
  982. STATIC void
  983. outflush(done)
  984. int    done;
  985. {
  986. X    int    wrstat;
  987. X
  988. X    /*
  989. X     * in this case we are a floppy and want to write the floppy from one
  990. X     * buffer (to have a copy of the data to verify against)
  991. X     */
  992. X    bufend = buffer + (aruntil ? min(buflen, arleft) : buflen);
  993. X    if (Fflag && (done == NOTDONE) && ((bufend - bufidx) > 0))
  994. X    {    return;
  995. X    }
  996. X
  997. X    if (aruntil && arleft == 0)
  998. X        next(O_WRONLY, "Output limit reached");
  999. X
  1000. X    /*
  1001. X     * if we are a floppy open the disk at the last moment
  1002. X     * call verify w/ an error if the disk can't be opened
  1003. X     */
  1004. X    if (Fflag)
  1005. X    {
  1006. X        if (nextopen(O_WRONLY) < 0)
  1007. X        {
  1008. X            verifycnt = 0;
  1009. X            verify(1);
  1010. X            if (done == NOTDONE)
  1011. X                next(O_WRONLY, "Disk's output limit reached (disk one)");
  1012. X            bufend = (bufidx = buffer) + (aruntil ? min(buflen, arleft) : buflen);
  1013. X            return;
  1014. X        }
  1015. X    }
  1016. X    if (fflag) {
  1017. X        outwait();
  1018. X        if ((outpid = xfork("outflush()", DIE)) == 0)
  1019. X            VOID nice(-40);
  1020. X    }
  1021. X
  1022. X    if (!fflag || outpid == 0) {
  1023. X        wrstat = writedisk(1);
  1024. X        if (Fflag && verifyflag)
  1025. X        {    verifycnt = 0;
  1026. X            verify(wrstat);
  1027. X            if (done == NOTDONE)
  1028. X                next(O_WRONLY, "Disk's output limit reached");
  1029. X        }
  1030. X
  1031. X    }
  1032. X    if (fflag) {
  1033. X        if (outpid == 0)
  1034. X            _exit(0);
  1035. X        else
  1036. X            arleft -= bufidx - buffer;
  1037. X    }
  1038. X    bufend = (bufidx = buffer) + (aruntil ? min(buflen, arleft) : buflen);
  1039. }
  1040. X
  1041. /*
  1042. X * outhead()
  1043. X *
  1044. X * Write an archive header.
  1045. X */
  1046. STATIC void
  1047. outhead(name, asb)
  1048. reg char    *name;
  1049. reg Stat    *asb;
  1050. {
  1051. X    reg uint    namelen;
  1052. X    auto char    header[M_STRLEN + H_STRLEN + 1];
  1053. X
  1054. X    if ((name[0] == '/') && !abspaths)
  1055. X        if (name[1])
  1056. X            ++name;
  1057. X        else
  1058. X            name = ".";
  1059. X    namelen = (uint) strlen(name) + 1;
  1060. X    VOID strcpy(header, M_ASCII);
  1061. X    VOID sprintf(header + M_STRLEN, H_PRINT, ush(asb->sb_dev),
  1062. X        ush(asb->sb_ino), ush(asb->sb_mode), ush(asb->sb_uid),
  1063. X        ush(asb->sb_gid), ush(asb->sb_nlink), ush(asb->sb_rdev),
  1064. X        mflag ? timenow : asb->sb_mtime, namelen, asb->sb_size);
  1065. X    outwrite(header, M_STRLEN + H_STRLEN);
  1066. X    outwrite(name, namelen);
  1067. #ifdef    S_IFLNK
  1068. X    if ((asb->sb_mode & S_IFMT) == S_IFLNK)
  1069. X        outwrite(asb->sb_link, (uint) asb->sb_size);
  1070. #endif    /* S_IFLNK */
  1071. }
  1072. X
  1073. /*
  1074. X * outpad()
  1075. X *
  1076. X * Pad the archive.
  1077. X */
  1078. STATIC void
  1079. outpad(pad)
  1080. reg off_t    pad;
  1081. {
  1082. X    reg int        idx;
  1083. X    reg int        len;
  1084. X
  1085. X    while (pad) {
  1086. X        if ((len = bufend - bufidx) > pad)
  1087. X            len = pad;
  1088. X        for (idx = 0; idx < len; ++idx)
  1089. X            *bufidx++ = '\0';
  1090. X        total += len;
  1091. X        outflush(NOTDONE);
  1092. X        pad -= len;
  1093. X    }
  1094. }
  1095. X
  1096. /*
  1097. X * outwait()
  1098. X *
  1099. X * Wait for the last background outflush() process (if any). The child
  1100. X * exit value is zero if successful, 255 if a write() returned zero or
  1101. X * the value of errno if a write() was unsuccessful.
  1102. X */
  1103. STATIC void
  1104. outwait()
  1105. {
  1106. X    auto int    status;
  1107. X
  1108. X    if (outpid == 0)
  1109. X        return;
  1110. X    status = xwait(outpid, "outwait()", TRUE);
  1111. X    outpid = 0;
  1112. X    if (status)
  1113. X        fatal(arspec, "Child error");
  1114. }
  1115. X
  1116. /*
  1117. X * outwrite()
  1118. X *
  1119. X * Write archive data.
  1120. X */
  1121. STATIC void
  1122. outwrite(idx, len)
  1123. reg char    *idx;
  1124. uint        len;
  1125. {
  1126. X    reg uint    have;
  1127. X    reg uint    want;
  1128. X    reg char    *endx = idx + len;
  1129. X
  1130. X    while (want = endx - idx) {
  1131. X        while ((have = bufend - bufidx) == 0)
  1132. X            outflush(NOTDONE);
  1133. X        if (have > want)
  1134. X            have = want;
  1135. X        memcpy(bufidx, idx, have);
  1136. X        bufidx += have;
  1137. X        idx += have;
  1138. X        total += have;
  1139. X    }
  1140. }
  1141. X
  1142. /*
  1143. X * pass()
  1144. X *
  1145. X * Copy within the filesystem.
  1146. X */
  1147. STATIC VOIDFN
  1148. pass(av)
  1149. reg char    **av;
  1150. {
  1151. X    reg int        fd;
  1152. X    reg char    **avx;
  1153. X    auto Stat    sb;
  1154. X    auto char    name[PATHSIZE];
  1155. X
  1156. X    for (avx = av; *avx; ++avx) {
  1157. X        if (gflag && **avx != '/')
  1158. X            fatal(*avx, "Relative pathname");
  1159. X        if (STAT(*avx, &sb) < 0)
  1160. X            fatal(*avx, syserr());
  1161. X        if ((sb.sb_mode & S_IFMT) != S_IFDIR)
  1162. X            fatal(*avx, "Not a directory");
  1163. X    }
  1164. X    while ((fd = openin(name, &sb)) >= 0) {
  1165. X        if (passitem(name, &sb, fd, av))
  1166. X            VOID close(fd);
  1167. X        if (vflag)
  1168. X        {    if (*uncompto)
  1169. X                VOID fprintf(stderr, "%s uncompressed to: %s\n",
  1170. X                         name, uncompto);
  1171. X            else
  1172. X                VOID fprintf(stderr, "%s\n", name);
  1173. X        }
  1174. X    }
  1175. }
  1176. X
  1177. /*
  1178. X * passdata()
  1179. X *
  1180. X * Copy data to one file. Doesn't believe in input file
  1181. X * descriptor zero (see description of kludge in openin()
  1182. X * comments). Closes the provided output file descriptor.
  1183. X */
  1184. STATIC void
  1185. passdata(from, ifd, to, ofd)
  1186. char        *from;
  1187. reg int        ifd;
  1188. char        *to;
  1189. reg int        ofd;
  1190. {
  1191. X    reg int        got;
  1192. X    reg int        sparse;
  1193. X    auto char    block[FSBUF];
  1194. X
  1195. X    if (ifd) {
  1196. X        VOID lseek(ifd, (off_t) 0, 0);
  1197. X        sparse = 0;
  1198. X        while ((got = read(ifd, block, sizeof(block))) > 0
  1199. X            && (sparse = fswrite(ofd, block, (uint) got)) >= 0)
  1200. X            total += got;
  1201. X        if (got)
  1202. X            VOID warn(got < 0 ? from : to, syserr());
  1203. X        else if (sparse > 0
  1204. X          && (lseek(ofd, (off_t) -sparse, 1) < 0
  1205. X            || write(ofd, block, (uint) sparse) != sparse))
  1206. X            VOID warn(to, syserr());
  1207. X    }
  1208. X    VOID close(ofd);
  1209. }
  1210. X
  1211. /*
  1212. X * passitem()
  1213. X *
  1214. X * Copy one file. Returns given input file descriptor.
  1215. X */
  1216. STATIC int
  1217. passitem(from, asb, ifd, dir)
  1218. char        *from;
  1219. Stat        *asb;
  1220. reg int        ifd;
  1221. reg char    **dir;
  1222. {
  1223. X    reg int        ofd;
  1224. X    auto time_t    tstamp[2];
  1225. X    auto char    to[PATHSIZE];
  1226. X
  1227. X    while (*dir) {
  1228. X        if (nameopt(strcat(strcat(strcpy(to, *dir++), "/"), from)) < 0)
  1229. X            continue;
  1230. X        if ((ofd = openotty(to, asb,
  1231. X            lflag ? linkto(from, asb) : linkfrom(asb), 1, Zflag)) < 0)
  1232. X            continue;
  1233. X        if (ofd > 0)
  1234. X            passdata(from, ifd, to, ofd);
  1235. X        tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
  1236. X        VOID utime(to, tstamp);
  1237. X        /* safety */
  1238. X        if (uncompressrun)
  1239. X        {    VOID xwait(uncompressrun, "passitem xwait()", TRUE);
  1240. X            uncompressrun = 0;
  1241. X        }
  1242. X    }
  1243. X    return (ifd);
  1244. }
  1245. X
  1246. /*
  1247. X * pipechld()
  1248. X *
  1249. X * Child portion of pipeline fork.
  1250. X */
  1251. STATIC int
  1252. pipechld(mode, pfd)
  1253. int        mode;
  1254. reg int        *pfd;
  1255. {
  1256. X    reg char    **av;
  1257. X    auto char    *arg[32];
  1258. X
  1259. X    av = arg;
  1260. X    if ((*av = getenv("SHELL")) && **av)
  1261. X        ++av;
  1262. X    else
  1263. X        *av++ = "/bin/sh";
  1264. X    *av++ = "-c";
  1265. X    *av++ = arname + 1;
  1266. X    *av = NULL;
  1267. X    if (mode) {
  1268. X        VOID close(pfd[1]);
  1269. X        VOID close(STDIN);
  1270. X        VOID dup(pfd[0]);
  1271. X        VOID close(pfd[0]);
  1272. X        VOID close(STDOUT);
  1273. X        VOID open("/dev/null", O_WRONLY);
  1274. X    } else {
  1275. X        VOID close(STDIN);
  1276. X        VOID open("/dev/null", O_RDONLY);
  1277. X        VOID close(pfd[0]);
  1278. X        VOID close(STDOUT);
  1279. X        VOID dup(pfd[1]);
  1280. X        VOID close(pfd[1]);
  1281. X    }
  1282. X    if (ttyf >= 0)
  1283. X        VOID close(ttyf);
  1284. X    VOID execvp(arg[0], arg);
  1285. X    VOID warn(arg[0], syserr());
  1286. X    _exit(1);
  1287. }
  1288. X
  1289. /*
  1290. X * pipeopen()
  1291. X *
  1292. X * Open an archive via a pipeline. Returns a file
  1293. X * descriptor, or -1 if unsuccessful.
  1294. X */
  1295. STATIC int
  1296. pipeopen(mode)
  1297. reg int        mode;
  1298. {
  1299. X    auto int    pfd[2];
  1300. X
  1301. X    if (pipe(pfd) < 0)
  1302. X        return (-1);
  1303. X    if ((pipepid = xfork("pipeopen()", DIE)) == 0)
  1304. X        pipechld(mode, pfd);
  1305. X    if (mode) {
  1306. X        VOID close(pfd[0]);
  1307. X        return (pfd[1]);
  1308. X    } else {
  1309. X        VOID close(pfd[1]);
  1310. X        return (pfd[0]);
  1311. X    }
  1312. }
  1313. X
  1314. /*
  1315. X * pipewait()
  1316. X *
  1317. X * Await a pipeline.
  1318. X */
  1319. STATIC void
  1320. pipewait()
  1321. {
  1322. X    reg int        status;
  1323. X
  1324. X    if (pipepid == 0)
  1325. X        return;
  1326. X    status = xwait(pipepid, "pipewait()", TRUE);
  1327. X    pipepid = 0;
  1328. X    if (status)
  1329. X        fatal(arspec, "Pipeline error");
  1330. }
  1331. X
  1332. /*
  1333. X * prsize()
  1334. X *
  1335. X * Print a file offset.
  1336. X */
  1337. STATIC void
  1338. prsize(stream, size)
  1339. FILE        *stream;
  1340. reg off_t    size;
  1341. {
  1342. X    reg off_t    n;
  1343. X
  1344. X    if (n = (size / (1024L * 1024L))) {
  1345. X        VOID fprintf(stream, "%ldm+", n);
  1346. X        size -= n * 1024 * 1024;
  1347. X    }
  1348. X    if (n = (size / 1024)) {
  1349. X        VOID fprintf(stream, "%ldk+", n);
  1350. X        size -= n * 1024;
  1351. X    }
  1352. X    VOID fprintf(stream, "%ld", size);
  1353. }
  1354. X
  1355. #ifndef    MKDIR
  1356. X
  1357. /*
  1358. X * rmdir()
  1359. X *
  1360. X * Remove a directory via "/bin/rmdir". Sets errno to a
  1361. X * questionably sane value upon failure.
  1362. X */
  1363. STATIC int
  1364. rmdir(name)
  1365. reg char    *name;
  1366. {
  1367. X    reg int        pid;
  1368. X
  1369. X    if ((pid = xfork("rmdir()", DIE)) == 0) {
  1370. X        VOID close(fileno(stdin));
  1371. X        VOID close(fileno(stdout));
  1372. X        VOID close(fileno(stderr));
  1373. X        VOID open("/dev/null", O_RDWR);
  1374. X        VOID dup(fileno(stdin));
  1375. X        VOID dup(fileno(stdin));
  1376. X        VOID execl("/bin/rmdir", "rmdir", name, (char *) NULL);
  1377. X        exit(1);
  1378. X    }
  1379. X    if (xwait(pid, "rmdir()", TRUE) == 0)
  1380. X        return (0);
  1381. X    errno = EACCES;
  1382. X    return (-1);
  1383. }
  1384. X
  1385. #endif    /* MKDIR */
  1386. X
  1387. /*
  1388. X * fswrite()
  1389. X *
  1390. X * Write a filesystem block. Seeks past sparse blocks. Returns
  1391. X * 0 if the block was written, the given length for a sparse
  1392. X * block or -1 if unsuccessful.
  1393. X */
  1394. STATIC int
  1395. fswrite(fd, buf, len)
  1396. int        fd;
  1397. char        *buf;
  1398. uint        len;
  1399. {
  1400. X    reg char    *bidx;
  1401. X    reg char    *bend;
  1402. X
  1403. X    if (jflag)
  1404. X        return (write(fd, buf, len) == len ? 0 : -1);
  1405. X    bend = (bidx = buf) + len;
  1406. X    while (bidx < bend)
  1407. X        if (*bidx++)
  1408. X            return (write(fd, buf, len) == len ? 0 : -1);
  1409. X    return (lseek(fd, (off_t) len, 1) < 0 ? -1 : len);
  1410. }
  1411. X
  1412. /*
  1413. X * syserr()
  1414. X *
  1415. X * Return pointer to appropriate system error message.
  1416. X */
  1417. STATIC char *
  1418. syserr()
  1419. {
  1420. X    static char    msg[40];
  1421. X
  1422. X    if (errno > 0 && errno < sys_nerr)
  1423. X        return (sys_errlist[errno]);
  1424. X    VOID sprintf(msg, "Unknown error (errno %d)", errno);
  1425. X    return (msg);
  1426. }
  1427. X
  1428. /*
  1429. X * toc()
  1430. X *
  1431. X * Print archive table of contents.
  1432. X */
  1433. STATIC VOIDFN
  1434. toc(av)
  1435. reg char    **av;
  1436. {
  1437. X    auto Stat    sb;
  1438. X    auto char    name[PATHSIZE];
  1439. X
  1440. X    if (*av)
  1441. X        fatal(*av, "Extraneous argument");
  1442. X    name[0] = '\0';
  1443. X    while (inhead(name, &sb) == 0) {
  1444. X        if (namecmp(name) == 0)
  1445. X            tocentry(name, &sb);
  1446. X        if (inskip(sb.sb_size) < 0)
  1447. X            VOID warn(name, "File data is corrupt");
  1448. X    }
  1449. }
  1450. X
  1451. /*
  1452. X * tocentry()
  1453. X *
  1454. X * Print a single table-of-contents entry.
  1455. X */
  1456. STATIC void
  1457. tocentry(name, asb)
  1458. char        *name;
  1459. reg Stat    *asb;
  1460. {
  1461. X    reg Time    *atm;
  1462. X    reg Link    *from;
  1463. X    reg Passwd    *pwp;
  1464. X    reg Group    *grp;
  1465. X    static char    *month[] = {
  1466. X        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1467. X        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1468. X    };
  1469. X
  1470. X    if (vflag) {
  1471. X        tocmode(asb->sb_mode);
  1472. X        VOID printf(" %2d", asb->sb_nlink);
  1473. X        atm = localtime(&asb->sb_mtime);
  1474. X        if (pwp = getpwuid(ush(asb->sb_uid)))
  1475. X            VOID printf(" %-8s", pwp->pw_name);
  1476. X        else
  1477. X            VOID printf(" %-8u", ush(asb->sb_uid));
  1478. X        if (grp = getgrgid(ush(asb->sb_gid)))
  1479. X            VOID printf(" %-8s", grp->gr_name);
  1480. X        else
  1481. X            VOID printf(" %-8u", ush(asb->sb_gid));
  1482. X        switch (asb->sb_mode & S_IFMT) {
  1483. X        case S_IFBLK:
  1484. X        case S_IFCHR:
  1485. X            VOID printf(" %3d, %3d",
  1486. X                major(asb->sb_rdev), minor(asb->sb_rdev));
  1487. X            break;
  1488. X        case S_IFREG:
  1489. X            VOID printf(" %8ld", asb->sb_size);
  1490. X            break;
  1491. X        default:
  1492. X            VOID printf("         ");
  1493. X        }
  1494. X        VOID printf(" %3s %2d %02d:%02d:%02d %4d ",
  1495. X            month[atm->tm_mon], atm->tm_mday, atm->tm_hour,
  1496. X            atm->tm_min, atm->tm_sec, atm->tm_year + 1900);
  1497. X    }
  1498. X    VOID printf("%s", name);
  1499. X    if (vflag || lflag) {
  1500. X        if (asb->sb_nlink > 1)
  1501. X            if (from = linkfrom(asb))
  1502. X                VOID printf(" -> %s",
  1503. X                    from->l_path->p_name);
  1504. X            else
  1505. X                VOID linkto(name, asb);
  1506. #ifdef    S_IFLNK
  1507. X        if ((asb->sb_mode & S_IFMT) == S_IFLNK)
  1508. X            VOID printf(" S-> %s", asb->sb_link);
  1509. #endif    /* S_IFLNK */
  1510. X    }
  1511. X    putchar('\n');
  1512. }
  1513. X
  1514. /*
  1515. X * tocmode()
  1516. X *
  1517. X * Fancy file mode display.
  1518. X */
  1519. STATIC void
  1520. tocmode(mode)
  1521. reg ushort    mode;
  1522. {
  1523. X    switch (mode & S_IFMT) {
  1524. X        case S_IFREG: putchar('-'); break;
  1525. X        case S_IFDIR: putchar('d'); break;
  1526. #ifdef    S_IFLNK
  1527. X        case S_IFLNK: putchar('l'); break;
  1528. #endif    /* S_IFLNK */
  1529. X        case S_IFBLK: putchar('b'); break;
  1530. X        case S_IFCHR: putchar('c'); break;
  1531. #ifdef    S_IFIFO
  1532. X        case S_IFIFO: putchar('p'); break;
  1533. #endif    /* S_IFIFO */
  1534. X        default:
  1535. X            VOID printf("[%o]", mode >> S_IFSHF);
  1536. X    }
  1537. X    putchar(mode & 0400 ? 'r' : '-');
  1538. X    putchar(mode & 0200 ? 'w' : '-');
  1539. X    putchar(mode & 0100
  1540. X        ? mode & 04000 ? 's' : 'x'
  1541. X        : mode & 04000 ? 'S' : '-');
  1542. X    putchar(mode & 0040 ? 'r' : '-');
  1543. X    putchar(mode & 0020 ? 'w' : '-');
  1544. X    putchar(mode & 0010
  1545. X        ? mode & 02000 ? 's' : 'x'
  1546. X        : mode & 02000 ? 'S' : '-');
  1547. X    putchar(mode & 0004 ? 'r' : '-');
  1548. X    putchar(mode & 0002 ? 'w' : '-');
  1549. X    putchar(mode & 0001
  1550. X        ? mode & 01000 ? 't' : 'x'
  1551. X        : mode & 01000 ? 'T' : '-');
  1552. }
  1553. X
  1554. /*
  1555. X * usage()
  1556. X *
  1557. X * Print a helpful message and exit.
  1558. X */
  1559. STATIC void
  1560. usage()
  1561. {
  1562. X    VOID fprintf(stderr, "\
  1563. Usage:    %s -o [ -fghlmuvzq ] [ -(bces) n ] [-F[KZL status_file][R format_command]s n]  archive\n\
  1564. X    %s -i [ -djkmnuvxz ] [ -(bcs) n ] [ -y prefix ] archive\n\
  1565. X    %s -t [ -kuvz ] [ -(bcs) n ] [ -y prefix ] archive\n\
  1566. X    %s -p [ -dghjlmnuvxz ] dir [ ... ]\n",
  1567. X        myname, myname, myname, myname);
  1568. X    exit(1);
  1569. }
  1570. X
  1571. /*
  1572. X * warn()
  1573. X *
  1574. X * Print a warning message. Always returns -1.
  1575. X */
  1576. STATIC int
  1577. warn(what, why)
  1578. char    *what;
  1579. char    *why;
  1580. {
  1581. X    long    dietime;
  1582. X    dietime = time((time_t *) NULL);
  1583. X
  1584. X    VOID fprintf(stderr,
  1585. X        "%s: \"%s\": %s\n",
  1586. X        myname, what, why);
  1587. X    if (logfile != (FILE *)0)
  1588. X        VOID fprintf(logfile, "%s: \"%s\": %s (disk %u) at %s\n",
  1589. X            myname, what, why, arvolume, ctime(&dietime));
  1590. X    return (-1);
  1591. }
  1592. X
  1593. /*
  1594. X * warnarch()
  1595. X *
  1596. X * Print an archive-related warning message, including
  1597. X * an adjusted file offset. Always returns -1.
  1598. X */
  1599. STATIC int
  1600. warnarch(msg, adjust)
  1601. char    *msg;
  1602. off_t    adjust;
  1603. {
  1604. X    VOID fprintf(stderr, "%s: \"%s\" [offset ", myname, arspec);
  1605. X    prsize(stderr, total - adjust);
  1606. X    VOID fprintf(stderr, "]: %s\n", msg);
  1607. X    return (-1);
  1608. }
  1609. X
  1610. /*
  1611. X * xfork()
  1612. X *
  1613. X * Create a child.
  1614. X */
  1615. STATIC int
  1616. xfork(what, die)
  1617. reg char    *what;
  1618. int    die;
  1619. {
  1620. X    reg int        pid;
  1621. X    reg Child    *cp;
  1622. X    reg int        idx;
  1623. X    static uint    delay[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 };
  1624. X
  1625. #ifdef SIGCHLD
  1626. X    VOID signal(SIGCHLD, SIG_DFL);    /* SysV mostly... */
  1627. else
  1628. X    VOID signal(SIGCLD, SIG_DFL);    /* some SysV's... */
  1629. #endif
  1630. X    for (idx = 0; (pid = fork()) < 0; ++idx) {
  1631. X        if (idx == sizeof(delay))
  1632. X            if (die)
  1633. X                fatal(arspec, syserr());
  1634. X            else
  1635. X                return(-1);
  1636. X        VOID warn(what, "Trouble forking...");
  1637. X        if (Fflag && !die)    /* give up and go on... */
  1638. X            return(-1);
  1639. X        sleep(delay[idx]);
  1640. X    }
  1641. X    if (idx)
  1642. X        VOID warn(what, "...successful fork");
  1643. X    cp = (Child *) memget(sizeof(*cp));
  1644. X    cp->c_pid = pid;
  1645. X    cp->c_flags = 0;
  1646. X    cp->c_status = 0;
  1647. X    cp->c_forw = children;
  1648. X    children = cp;
  1649. X    return (pid);
  1650. }
  1651. X
  1652. /*
  1653. X * xpause()
  1654. X *
  1655. X * Await a child.
  1656. X */
  1657. STATIC void
  1658. xpause()
  1659. {
  1660. X    reg Child    *cp;
  1661. X    reg int        pid;
  1662. X    auto int    status;
  1663. X
  1664. X    do {
  1665. X        while ((pid = wait(&status)) < 0)
  1666. X            ;
  1667. X        for (cp = children; cp && cp->c_pid != pid; cp = cp->c_forw)
  1668. X            ;
  1669. X    } while (cp == NULL);
  1670. X    cp->c_flags |= CF_EXIT;
  1671. X    cp->c_status = status;
  1672. }
  1673. X
  1674. /*
  1675. X * xwait()
  1676. X *
  1677. X * Find the status of a child.
  1678. X */
  1679. STATIC int
  1680. xwait(pid, what, compstat2)
  1681. reg int        pid;
  1682. char        *what;
  1683. int        compstat2;
  1684. {
  1685. X    reg int        status;
  1686. X    reg Child    *cp;
  1687. X    reg Child    **acp;
  1688. X    auto char    why[100];
  1689. X
  1690. X    for (acp = &children; cp = *acp; acp = &cp->c_forw)
  1691. X        if (cp->c_pid == pid)
  1692. X            break;
  1693. X    if (cp == NULL)
  1694. X        fatal(what, "Lost child");
  1695. X    while ((cp->c_flags & CF_EXIT) == 0)
  1696. X        xpause();
  1697. X    status = cp->c_status;
  1698. X    *acp = cp->c_forw;
  1699. X    free((char *) cp);
  1700. X    if (status == 0)
  1701. X        return (0);
  1702. X    if (status & 0377)
  1703. X        VOID sprintf(why, "Killed by signal %d%s",
  1704. X            status & 0177, status & 0200 ? " -- core dumped" : "");
  1705. X    else
  1706. X        VOID sprintf(why, "Exit %d", (status >> 8) & 0377);
  1707. X
  1708. X    if ((!compstat2 && (((status >> 8) & 0377) != 2)) || compstat2)
  1709. X        return (warn(what, why));
  1710. X    else
  1711. X        return ((status >> 8) & 0377);
  1712. }
  1713. X
  1714. /* right now we verify the whole disk */
  1715. void
  1716. verify(error)
  1717. int    error;
  1718. {    char    *verbuf;
  1719. X    char    *buf;
  1720. X    reg time_t    began;
  1721. X    int    got, readamt, len;
  1722. X    int    wrstat;
  1723. X    auto char    msg[200];
  1724. X    auto char    answer[20];
  1725. X
  1726. X    if (*arname == '!')
  1727. X    {    VOID warn("Can't verify a piped command", "");
  1728. X        return;
  1729. X    }
  1730. X    if (!error)
  1731. X    {    if ((verbuf = malloc(arbsize)) == NULL)
  1732. X            fatal(arspec, "Cannot allocate Verify I/O buffer");
  1733. X
  1734. X        /*
  1735. X         * close as O_WRONLY and reopen as O_RDONLY to verify (on a
  1736. X         * disk this is a good thing)
  1737. X         */
  1738. X        nextclos();
  1739. X        verifycnt++;
  1740. X        if (nextopen(O_RDONLY) < 0)
  1741. X        {    VOID warn("re-open for verify failed", "");
  1742. X            error = 1;
  1743. X        }
  1744. X        else
  1745. X        {   fprintf(stderr, "Verifying...\n");
  1746. X            for (buf = buffer; len = bufidx - buf; )
  1747. X            {
  1748. X            readamt = min(len, arbsize);
  1749. X            if ((got = read(arfd, verbuf, readamt)) == readamt)
  1750. X            {
  1751. #ifdef HAVEMEMCMP
  1752. X                if (memcmp(verbuf, buf, got) != 0)
  1753. #else
  1754. X                if (bcmp(verbuf, buf, got) != 0)
  1755. #endif
  1756. X                {    VOID warn("Verify failed", "");
  1757. X                    error = 1;
  1758. X                    break;
  1759. X                }
  1760. X                else
  1761. X                    buf += got;
  1762. X            }
  1763. X            else
  1764. X            {    VOID warn("Read returned short", "");
  1765. X            fprintf(stderr, "Read %d wanted %d bytes\n", got,
  1766. X                    readamt);
  1767. X                error = 1;
  1768. X                break;
  1769. X            }
  1770. X            }
  1771. X        }
  1772. X        free(verbuf);
  1773. X    }
  1774. X    if (error)
  1775. X    {    int    answernum = 0;
  1776. X
  1777. X        for (;;)
  1778. X        {
  1779. X            /*
  1780. X             * answernum == 3 here means the format worked and we want
  1781. X             * to try to write the disk (answernum == 1)
  1782. X             */
  1783. X            if (answernum == 3)
  1784. X            answernum = 1;
  1785. X            else
  1786. X            {
  1787. X            /* don't count time waiting for the user */
  1788. X            began = time((time_t *) NULL);
  1789. X            VOID sprintf(msg, "\
  1790. %s: %s of disk %u has FAILED (try option #3 first)!\07\n\
  1791. \tEnter 1 to RETRY this disk\n\
  1792. \tEnter 2 to REFORMAT this disk\n\07\
  1793. \tEnter 3 to REFORMAT AND THEN RETRY this disk if the format works\n%s",
  1794. X                myname,
  1795. X                ((error && (verifycnt == 0)) ? "Writing" :
  1796. X                    "Verify"),
  1797. X                arvolume, hidequit ? "" :
  1798. X                "\tEnter \"quit\" to ABORT the backup\n\07");
  1799. X            nextask(msg, answer, sizeof(answer));
  1800. X            timewait += time((time_t *) NULL) - began;
  1801. X            answernum = atoi(answer);
  1802. X            }
  1803. X
  1804. X            if (answernum == 1)    /* note: recursive here... */
  1805. X            {    nextclos();
  1806. X            /* if we can't open, try again */
  1807. X            if (nextopen(O_WRONLY) < 0)
  1808. X                continue;
  1809. X            wrstat = writedisk(0);
  1810. X                /* if we failed or we are verifing */
  1811. X            if (wrstat || (Fflag && verifyflag))
  1812. X                verify(wrstat);
  1813. X            break;
  1814. X            }
  1815. X            else
  1816. X            if ((answernum == 2) || (answernum == 3))
  1817. X            {    if (system(formatcmd) != 0)
  1818. X            {    fprintf(stderr, "Format failed!\n");
  1819. X                answernum = 0; /* error, don't autowrite */
  1820. X            }
  1821. X            else
  1822. X                fprintf(stderr, "Format successful!\n");
  1823. X            }
  1824. X            else
  1825. X            if (strcmp(answer, "quit") == 0)
  1826. X            fatal(arspec, "Quiting during a verify");
  1827. X        }
  1828. X    }
  1829. }
  1830. X
  1831. int
  1832. writedisk(realwrite)
  1833. int    realwrite;
  1834. {
  1835. X    reg char    *buf;
  1836. X    reg int        got;
  1837. X    reg uint    len;
  1838. X
  1839. X    if (Fflag)
  1840. X        fprintf(stderr, "Writing the disk...\n");
  1841. #if ((defined (USESHMEM)) && (defined (UNIXPC)))
  1842. X    /*
  1843. X     * stupid 3b1 will block in a write to a floppy from shared memory
  1844. X     * (tested on Unix3.51[ ac])
  1845. X     */
  1846. X    if ((tbuf = malloc(arbsize)) == (char *)0)
  1847. X    {    fatal("writedisk malloc failed", syserr());
  1848. X    }
  1849. #endif
  1850. X    for (buf = buffer; len = bufidx - buf; ) {
  1851. #if ((defined (USESHMEM)) && (defined (UNIXPC)))
  1852. X        memcpy(tbuf, buf, min(len, arbsize));
  1853. X        if ((got = write(arfd, tbuf,
  1854. #else
  1855. X        if ((got = write(arfd, buf,
  1856. #endif
  1857. X            *arname == '!' ? len : min(len, arbsize))) > 0) {
  1858. X            buf += got;
  1859. X            if (realwrite)
  1860. X                arleft -= got;
  1861. X        } else if (fflag) {
  1862. X            VOID warn(arspec, got < 0
  1863. X                ? syserr()
  1864. X                : "Apparently full");
  1865. X            _exit(1);
  1866. X        } else if (got < 0) {
  1867. X            /*fatal(arspec, syserr());*/
  1868. X            VOID warn(arspec, syserr());
  1869. X            return(1);
  1870. X        }
  1871. X        else
  1872. X        {
  1873. /* check here if verifying... */
  1874. X            next(O_WRONLY, "Apparently full");
  1875. X            return(1);
  1876. X        }
  1877. X    }
  1878. #if ((defined (USESHMEM)) && (defined (UNIXPC)))
  1879. X    free(tbuf);
  1880. #endif
  1881. X    return(0);
  1882. }
  1883. X
  1884. /*
  1885. X * compress "name" if we can
  1886. X * If we compress we change the statbuf size, the file name, close
  1887. X * the old pointer to the file and return the pointer to the compressed
  1888. X * version;
  1889. X */
  1890. #include <sys/dir.h>
  1891. void
  1892. compressfile(fdp, name, asb)
  1893. int    *fdp;
  1894. char    *name;
  1895. reg Stat    *asb;
  1896. {
  1897. X    int        compout;
  1898. X    char        *tmpcomp;
  1899. X    Stat        asb2;
  1900. X    int        comppid;
  1901. X    int        namelen;
  1902. X
  1903. X    namelen= strlen(name);
  1904. X    /* compress only if no links or not already compressed */
  1905. X    if (!lflag && (asb->sb_nlink == 1) && (namelen > 2) &&
  1906. #ifdef NOCOMPARCS
  1907. X            /* try to compress arc,zip,zoo files */
  1908. X            (strcmp(name+namelen-2, ".Z") != 0))
  1909. #else
  1910. X            /* things we know that don't compress */
  1911. X            (strcmp(name+namelen-2, ".Z") != 0) &&
  1912. X            (namelen > 4) &&
  1913. X            (strcmp(name+namelen-4, ".arc") != 0) &&
  1914. X            (strcmp(name+namelen-4, ".ARC") != 0) &&
  1915. X            (strcmp(name+namelen-4, ".gif") != 0) &&
  1916. X            (strcmp(name+namelen-4, ".GIF") != 0) &&
  1917. X            (strcmp(name+namelen-4, ".zip") != 0) &&
  1918. X            (strcmp(name+namelen-4, ".ZIP") != 0) &&
  1919. X            (strcmp(name+namelen-4, ".zoo") != 0) &&
  1920. X            (strcmp(name+namelen-4, ".ZOO") != 0))
  1921. #endif
  1922. X    {
  1923. X        /* make sure compress could put on the .Z */
  1924. X        if ((tmpcomp = strrchr(name, '/')) != NULL)
  1925. X            tmpcomp++;
  1926. X        else
  1927. X            tmpcomp = name;
  1928. #ifdef MAXNAMLEN    /* BSD otherwise should be sysV (FFS on sysV?) */
  1929. X        if (strlen(tmpcomp)+2 > MAXNAMLEN)
  1930. #else
  1931. X        if (strlen(tmpcomp)+2 > DIRSIZ)
  1932. #endif
  1933. X        {
  1934. #ifndef LONGZFILE
  1935. X            VOID warn(name, " is too long to tack on .Z");
  1936. X            return;
  1937. #endif
  1938. X        }
  1939. X
  1940. X        tmpcomp = tempnam(NULL, "afiot");
  1941. X        VOID unlink(tmpcomp);
  1942. X
  1943. X        if ((comppid = xfork("out(), compressing", NODIE)) == 0)
  1944. X        {    /* here we paste tmpcomp in place of stdout */
  1945. X            VOID close(fileno(stdout));
  1946. X            if (open(tmpcomp, O_WRONLY|O_CREAT|O_TRUNC, 0600) >= 0)
  1947. X            {
  1948. X                /*
  1949. X                 * paste name in place of stdin to allow for
  1950. X                 * .Z files longer than the filesystem allows.
  1951. X                 * YOU CAN then only uncompress from inside of
  1952. X                 * afio or un-afioing on BSD
  1953. X                 */
  1954. X                VOID close(fileno(stdin));
  1955. X                if (open(name, O_RDONLY) >= 0)
  1956. X                    execlp("compress", "compress", "-c", 0);
  1957. X            }
  1958. X            else
  1959. X                VOID warn("open compress for output failed", syserr());
  1960. X            exit(1);
  1961. X        }
  1962. X        if ((comppid > 0) &&
  1963. X            (xwait(comppid, "out(), wait for child", FALSE) == 0))
  1964. X        {
  1965. X            if ((hflag ? STAT(tmpcomp, &asb2) :
  1966. X                LSTAT(tmpcomp, &asb2)) >= 0)
  1967. X            {
  1968. X                if ((compout = open(tmpcomp, O_RDONLY, 0400)) > 0)
  1969. X                {
  1970. X                    if (asb2.sb_size < asb->sb_size)
  1971. X                    {    close(*fdp);
  1972. X                        strcat(name, ".Z");
  1973. X                        asb->sb_size = asb2.sb_size;
  1974. X                        *fdp = compout;
  1975. X                    }
  1976. X                }
  1977. X            }
  1978. X        }
  1979. X
  1980. X        /*
  1981. X         * assume the open descriptor above will still access the file
  1982. X         */
  1983. X        if (tmpcomp)
  1984. X            unlink(tmpcomp);
  1985. X    }
  1986. }
  1987. X
  1988. #ifdef USESHMEM
  1989. extern char    *shmat();
  1990. int    memids[NUMSHKEYS];
  1991. char    *memlocs[NUMSHKEYS];
  1992. int    indx = 0;
  1993. X
  1994. /* in this malloc we assume the memory segments will be allocated in order */
  1995. char *
  1996. shmemalloc(buflen, arname)
  1997. uint    buflen;        /* Archive buffer length */
  1998. char    *arname;
  1999. {
  2000. X    int    size;
  2001. X    key_t    shkey;
  2002. X
  2003. X    do {
  2004. X        if (indx == NUMSHKEYS)
  2005. X            fatal("Too many shared memory keys", "");
  2006. X        shkey = ftok(arname, (char)indx);
  2007. X        size = min(SHMEMSIZE, buflen);
  2008. X        if ((memids[indx] = shmget(shkey, size, IPC_CREAT|0666)) < 0) {
  2009. X            fatal("shmget failed", syserr());
  2010. X        }
  2011. X        if ((memlocs[indx] = shmat(memids[indx], 0, 0)) == (char *)-1) {
  2012. X            fatal("shmat failed", syserr());
  2013. X        }
  2014. X        indx++;
  2015. X        buflen -= size;
  2016. X    } while (buflen > 0);
  2017. X    return(memlocs[0]);
  2018. }
  2019. X
  2020. void
  2021. shmemfree()
  2022. {    for(--indx; indx >= 0; indx--)
  2023. X        if (shmctl(memids[indx], IPC_RMID, NULL) < 0) {
  2024. X            VOID warn("shmctl failed (shmemfree)\n", syserr());
  2025. X    }
  2026. }
  2027. #endif /* USESHMEM */
  2028. X
  2029. void
  2030. goodbye(status)
  2031. int    status;
  2032. {
  2033. #ifdef USESHMEM
  2034. X    shmemfree();
  2035. #endif
  2036. X    /* log that we died */
  2037. X    if (status && (logfile != (FILE *)0))
  2038. X    {    long    dietime;
  2039. X        dietime = time((time_t *) NULL);
  2040. X
  2041. X        VOID fprintf(logfile, "%s: the backup has failed (status %d), died at %s",
  2042. X            myname, status, ctime(&dietime));
  2043. X
  2044. X    }
  2045. X        
  2046. X    exit(status);
  2047. }
  2048. X
  2049. #ifdef MYTEMPNAM
  2050. /* author:    Monty Walls
  2051. X * written:    4/17/89
  2052. X * Copyright:    Copyright (c) 1989 by Monty Walls.
  2053. X *        Not derived from licensed software.
  2054. X *
  2055. X *        Permission to copy and/or distribute granted under the
  2056. X *        following conditions:
  2057. X *    
  2058. X *        1). This notice must remain intact.
  2059. X *        2). The author is not responsible for the consequences of use
  2060. X *            this software, no matter how awful, even if they
  2061. X *            arise from defects in it.
  2062. X *        3). Altered version must not be represented as being the 
  2063. X *            original software.
  2064. X */
  2065. X
  2066. #define MAXPREFIX    5
  2067. #define TMPNAME        "tmp"
  2068. #ifndef P_tmpdir
  2069. #define P_tmpdir    "/tmp"
  2070. #define L_tmpnam    14
  2071. #endif
  2072. X
  2073. extern char *mktemp();
  2074. extern char *strcat();
  2075. extern char *strcpy();
  2076. extern char *getenv();
  2077. X
  2078. char *
  2079. tempnam(dir, name)
  2080. char *dir;
  2081. char *name;
  2082. {
  2083. X    char *buf, *tmpdir;
  2084. X    
  2085. X    /* 
  2086. X     * This is kind of like the chicken & the egg.
  2087. X     * Do we use the users preference or the programmers?
  2088. X     */
  2089. #ifdef USE_ENV_VAR     
  2090. X    if ((tmpdir = getenv("TMPDIR")) == (char *)NULL) {
  2091. X        if ((tmpdir = dir) == (char *)NULL)
  2092. X            tmpdir = P_tmpdir;
  2093. X    }
  2094. #else
  2095. X    if ((tmpdir = dir) == (char *)NULL) {
  2096. X        if ((tmpdir = getenv("TMPDIR")) == (char *)NULL)
  2097. X            tmpdir = P_tmpdir;
  2098. X    }
  2099. #endif
  2100. X    /* now lets check and see if we can work there */
  2101. X    if (access(tmpdir, R_OK+W_OK+X_OK) < 0)
  2102. X        return ((char *)NULL);
  2103. X            
  2104. X    if (name == (char *)NULL) 
  2105. X        name = TMPNAME;
  2106. X    else if (strlen(name) > MAXPREFIX)
  2107. X        name[5] = '\0';    /* this is according to SYS5 */
  2108. X    
  2109. X    /* the magic value 2 is for '\0' & '/' */
  2110. X    if ((buf = (char *)malloc(L_tmpnam + strlen(tmpdir) + 2)) == (char *)NULL)
  2111. X        return ((char *)NULL);
  2112. X        
  2113. X    strcpy(buf, tmpdir);
  2114. X    strcat(buf, "/");
  2115. X    strcat(buf, name);
  2116. X    strcat(buf, ".XXXXXX");
  2117. X    
  2118. X    /* pass our completed pattern to mktemp */
  2119. X    return (mktemp(buf));
  2120. }
  2121. #endif /* MYTEMPNAM */
  2122. SHAR_EOF
  2123. echo 'File afio.c is complete' &&
  2124. chmod 0444 afio.c ||
  2125. echo 'restore of afio.c failed'
  2126. Wc_c="`wc -c < 'afio.c'`"
  2127. test 76841 -eq "$Wc_c" ||
  2128.     echo 'afio.c: original size 76841, current size' "$Wc_c"
  2129. rm -f _shar_wnt_.tmp
  2130. fi
  2131. # ============= dodsk ==============
  2132. if test -f 'dodsk' -a X"$1" != X"-c"; then
  2133.     echo 'x - skipping dodsk (File already exists)'
  2134.     rm -f _shar_wnt_.tmp
  2135. else
  2136. > _shar_wnt_.tmp
  2137. echo 'x - extracting dodsk (Text)'
  2138. sed 's/^X//' << 'SHAR_EOF' > 'dodsk' &&
  2139. #
  2140. # dodsk allows easy backup to the default drive using afio
  2141. #    Version 2.3
  2142. #
  2143. # for a 3b1 (UNIXPC)
  2144. #    1) Put a formatted floppy in the drive
  2145. #    2) /etc/iv -tv /dev/rfp020
  2146. #    3) Partition 1 (/dev/rfp021) insert that number into the -s flag
  2147. #        valid numbers are formatted as ###[bmk]
  2148. #        b=512, k=1024, m=1048576 (ex: 1m5k105)
  2149. #
  2150. # 3b1 (UNIXPC) 5.25" 395k, high density format (part 0 is 5k)
  2151. #DISKSIZE=395k
  2152. #FORMAT='iv -iv /dev/rfp020 /usr/lib/iv/FD10nl'
  2153. # 3.5" 720k floppy
  2154. #DISKSIZE=795k
  2155. #FORMAT='iv -iv /dev/rfp020 /usr/lib/iv/FDnl'
  2156. #DEVICE=/dev/rfp021
  2157. X
  2158. # 1.2M (whole disk) drive under Unix SysV 3.2
  2159. DISKSIZE=1200k
  2160. FORMAT=format\ -v\ /dev/rdsk/f05ht
  2161. DEVICE=/dev/rdsk/f05ht
  2162. # 1.44M
  2163. #DISKSIZE=1440k
  2164. #FORMAT=format\ -v\ /dev/rdsk/f03ht
  2165. #DEVICE=/dev/rdsk/f03ht
  2166. X
  2167. afio -ovzFKZ -L./BackupLog -s$DISKSIZE -R$FORMAT $DEVICE
  2168. SHAR_EOF
  2169. chmod 0555 dodsk ||
  2170. echo 'restore of dodsk failed'
  2171. Wc_c="`wc -c < 'dodsk'`"
  2172. test 809 -eq "$Wc_c" ||
  2173.     echo 'dodsk: original size 809, current size' "$Wc_c"
  2174. rm -f _shar_wnt_.tmp
  2175. fi
  2176. # ============= patchlevel.h ==============
  2177. if test -f 'patchlevel.h' -a X"$1" != X"-c"; then
  2178.     echo 'x - skipping patchlevel.h (File already exists)'
  2179.     rm -f _shar_wnt_.tmp
  2180. else
  2181. > _shar_wnt_.tmp
  2182. echo 'x - extracting patchlevel.h (Text)'
  2183. sed 's/^X//' << 'SHAR_EOF' > 'patchlevel.h' &&
  2184. #define VERSION    "2.3"
  2185. #define DATE    "25 Sep 91"
  2186. X
  2187. /*
  2188. X * Version 1.68        1985        Mark Brukhartz
  2189. X * Version 2.3        25 Sep 91    comp.sources.misc
  2190. X */
  2191. SHAR_EOF
  2192. chmod 0666 patchlevel.h ||
  2193. echo 'restore of patchlevel.h failed'
  2194. Wc_c="`wc -c < 'patchlevel.h'`"
  2195. test 137 -eq "$Wc_c" ||
  2196.     echo 'patchlevel.h: original size 137, current size' "$Wc_c"
  2197. rm -f _shar_wnt_.tmp
  2198. fi
  2199. rm -f _shar_seq_.tmp
  2200. echo You have unpacked the last part
  2201. exit 0
  2202. exit 0 # Just in case...
  2203. -- 
  2204. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2205. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2206. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2207. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2208.