home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume41 / wwfs / part13 < prev    next >
Encoding:
Text File  |  1994-01-17  |  88.9 KB  |  3,480 lines

  1. Newsgroups: comp.sources.misc
  2. From: youki-k@is.aist-nara.ac.jp (Youki Kadobayashi)
  3. Subject: v41i098:  wwfs - WorldWide File System, Part13/22
  4. Message-ID: <1994Jan17.202348.20120@sparky.sterling.com>
  5. X-Md4-Signature: be284f556928513a7a4c2d3107b50bdc
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Nara Institute of Science and Technology, Japan
  8. Date: Mon, 17 Jan 1994 20:23:48 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: youki-k@is.aist-nara.ac.jp (Youki Kadobayashi)
  12. Posting-number: Volume 41, Issue 98
  13. Archive-name: wwfs/part13
  14. Environment: UNIX, inet
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # Contents:  csd/dir.c csd/ftp_list.c csd/root.c csd/uip.c
  21. #   gtr/resolv.pl mosaic/htget.pl mosaic/url.pl
  22. # Wrapped by kent@sparky on Sun Jan 16 17:48:35 1994
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 13 (of 22)."'
  26. if test -f 'csd/dir.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'csd/dir.c'\"
  28. else
  29.   echo shar: Extracting \"'csd/dir.c'\" \(10665 characters\)
  30.   sed "s/^X//" >'csd/dir.c' <<'END_OF_FILE'
  31. X/* 
  32. X * WorldWide File System
  33. X * Copyright (c) 1992,1993 Youki Kadobayashi
  34. X * Copyright (c) 1992,1993 Osaka University
  35. X * All rights reserved.
  36. X *
  37. X * Permission to use, copy, modify and distribute this software and its
  38. X * documentation is hereby granted, provided that the following conditions
  39. X * are met:
  40. X * 1. Both the copyright notice and this permission notice appear in
  41. X *    all copies of the software, derivative works or modified versions,
  42. X *    and any portions thereof, and that both notices appear in
  43. X *    supporting documentation.
  44. X * 2. All advertising materials mentioning features or use of this software
  45. X *    must display the following acknowledgement:
  46. X *      This product includes software developed by the Osaka University
  47. X *      and its contributors.
  48. X * 3. Neither the name of the University nor the names of its contributors
  49. X *    may be used to endorse or promote products derived from this software
  50. X *    without specific prior written permission.
  51. X *
  52. X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND OSAKA
  53. X * UNIVERSITY DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  54. X * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  55. X *
  56. X * Osaka University requests users of this software to return to
  57. X *
  58. X *  Youki Kadobayashi
  59. X *  Department of Information and Computer Sciences
  60. X *  Osaka University, Toyonaka 560, Osaka, Japan
  61. X *
  62. X * any improvements or extensions that they make and grant Osaka
  63. X * University the rights to redistribute these changes.
  64. X */
  65. X/* directory management routines */
  66. Xstatic char *AtFSid = "$Header: dir.c[109.0] Wed Nov 24 03:47:07 1993 youki-k@is.aist-nara.ac.jp saved $";
  67. X
  68. X#include <sys/types.h>
  69. X#include <sys/stat.h>        /* for struct stat */
  70. X#include <fcntl.h>        /* for O_WRONLY etc. */
  71. X#include <string.h>
  72. X#include <stdio.h>
  73. X#include "wfs.h"
  74. X#include "util.h"
  75. X#include "global.h"
  76. X
  77. X/* not used actually. */
  78. Xstruct save_file {
  79. X    long    fileid;
  80. X    int    namelen;
  81. X    char    *name;
  82. X    int    linklen;
  83. X    char    *link;
  84. X    struct    fattr *fattr;
  85. X};
  86. X
  87. X/* not used actually. */
  88. Xstruct save_dir {
  89. X#define    WF_DIR_MAGIC    0xbaddeaL
  90. X    long    magic;
  91. X    int    namelen;
  92. X    char    *name;        /* entire directory name */
  93. X    long    ctime;
  94. X    int    nfile;
  95. X    struct    save_file *file;
  96. X};
  97. X
  98. Xwf_dir *dir_load();
  99. X
  100. Xtypedef struct {
  101. X    qelem    q;
  102. X    wf_dir    *dir;
  103. X} wf_dirq;
  104. X
  105. Xextern qelem dir_head;
  106. Xqelem dir_head = { &dir_head, &dir_head };        /* chain of wf_dirq */
  107. Xstatic void *dir_callout;
  108. X
  109. Xextern qelem olddir_head;
  110. Xqelem olddir_head = { &olddir_head, &olddir_head };    /* chain of wf_dir */
  111. X
  112. Xstatic void dir_gc(), dir_free();
  113. X
  114. Xvoid
  115. Xdir_start()
  116. X{
  117. X    dir_callout = timeout_set(gettime()+60, dir_gc, 0);
  118. X}
  119. X
  120. Xstatic void
  121. Xdir_gc()
  122. X{
  123. X    wf_dirq *p, *p2;
  124. X
  125. X    ITER2(p, p2, wf_dirq, &dir_head) {
  126. X        if (p->dir->flag & WF_DIR_WIREDDOWN || p->dir->n_xfer)
  127. X            continue;
  128. X        p->dir->idle += 60;
  129. X        if (p->dir->idle > WF_DIR_TTLMEM) {
  130. X            q_remove(p);
  131. X            dir_free(p->dir);
  132. X            FREE(p);
  133. X        }
  134. X    }
  135. X    dir_callout = timeout_set(gettime()+60, dir_gc, 0);
  136. X}
  137. X
  138. Xvoid
  139. Xdir_addfile(dirp, filep)
  140. Xwf_dir *dirp;
  141. Xwf_file *filep;
  142. X{
  143. X    q_insert(filep, LAST(wf_file, &dirp->file->q));
  144. X}
  145. X
  146. Xvoid
  147. Xdir_deletefile(filep)
  148. Xwf_file *filep;
  149. X{
  150. X    q_remove(filep);
  151. X}
  152. X
  153. X/* subdirectory */
  154. Xwf_file *
  155. Xdir_adddir(dirp, name, volid, dirid)
  156. Xwf_dir *dirp;
  157. Xchar *name;
  158. Xlong volid, dirid;
  159. X{
  160. X    wf_file *filep;
  161. X
  162. X    filep = file_alloc();
  163. X    attr_initdir(&filep->fattr);
  164. X    filep->name = strdup(name);
  165. X    filep->fattr.fsid = volid;
  166. X    filep->id = filep->fattr.fileid = dirid;
  167. X    filep->crc = updcrc(0L, name, strlen(name)+1);
  168. X    dir_addfile(dirp, filep);
  169. X    return filep;
  170. X}
  171. X
  172. Xstatic wf_dir *
  173. Xdir_alloc(volp)
  174. Xwf_vol *volp;
  175. X{
  176. X    wf_dir *dirp;
  177. X    wf_dirq *q;
  178. X
  179. X    dirp = ALLOC(wf_dir);
  180. X    dirp->file = (wf_file *) q_alloc();
  181. X    q_insert(dirp, volp->dirp);
  182. X
  183. X    q = ALLOC(wf_dirq);
  184. X    q->dir = dirp;
  185. X    q_insert(q, &dir_head);
  186. X    return dirp;
  187. X}
  188. X
  189. Xstatic void
  190. Xdir_free(dirp)
  191. Xwf_dir *dirp;
  192. X{
  193. X    wf_file *filep, *filep2;
  194. X
  195. X    file_uncache(dirp);
  196. X    if (dirp->id == 0) {
  197. X        syslog(LOG_WARNING, "dirp->id == 0");
  198. X    }
  199. X#ifdef DEBUG_GC
  200. X    dlog("free wf_dir \"%s\"", dirp->name);
  201. X#endif
  202. X    ITER2 (filep, filep2, wf_file, &dirp->file->q) {
  203. X        file_free(filep);
  204. X    }
  205. X    FREE(dirp->file);
  206. X    q_remove(dirp);
  207. X    FREE(dirp);
  208. X}
  209. X
  210. Xstatic void
  211. Xdir_makeobsolete(dirp)
  212. Xwf_dir *dirp;
  213. X{
  214. X    q_remove(dirp);
  215. X    q_insert(dirp, &olddir_head);
  216. X}
  217. X
  218. Xwf_dir *
  219. Xdir_new(volp, id, dir, subdir)
  220. Xwf_vol *volp;
  221. Xlong id;
  222. Xchar *dir, *subdir;
  223. X{
  224. X    wf_dir *dirp;
  225. X    int dirlen;
  226. X
  227. X    if ((dirp = dir_findcache(volp, id)) != (wf_dir *)0) {
  228. X        dir_makeobsolete(dirp);
  229. X    }
  230. X    dirp = dir_alloc(volp);
  231. X    dirp->id = id;
  232. X    dirp->ctime = gettime();
  233. X    if (dir && subdir) {
  234. X        dirlen = strlen(dir);
  235. X        dirp->name = malloc(dirlen + strlen(subdir) + 2);
  236. X        if (dirlen && dir[dirlen-1] == '/') {
  237. X            sprintf(dirp->name, "%s%s", dir, subdir);
  238. X        } else if (! strcmp(subdir, ".")) {
  239. X            /* avoid "foo/./././." */
  240. X            sprintf(dirp->name, "%s", dir);
  241. X        } else {
  242. X            sprintf(dirp->name, "%s/%s", dir, subdir);
  243. X        }
  244. X    } else {
  245. X        dirp->name = strdup("/");
  246. X    }
  247. X    return dirp;
  248. X}
  249. X
  250. Xwf_dir *
  251. Xdir_findcache(volp, dirid)
  252. Xwf_vol *volp;
  253. Xlong dirid;
  254. X{
  255. X    wf_dir *dirp;
  256. X    qelem *q;
  257. X
  258. X    q = &volp->dirp->q;
  259. X    /* search memory cache */
  260. X    ITER(dirp, wf_dir, q) {
  261. X        if (dirp->id == dirid) {
  262. X            if (dirp->idle > 0)
  263. X                dirp->idle = 0;
  264. X            goto found;
  265. X        }
  266. X    }
  267. X
  268. X    /* search disk cache */
  269. X    dirp = dir_load(volp, dirid);
  270. X
  271. X found:
  272. X    /* check freshness */
  273. X    if (dirp && !(dirp->flag & WF_DIR_WIREDDOWN)) {
  274. X        if (gettime() - dirp->ctime > WF_DIR_TTLDISK
  275. X            || volp->mtime > dirp->ctime)
  276. X            dirp->flag |= WF_DIR_OBSOLETE;
  277. X    }
  278. X    return dirp;
  279. X}
  280. X
  281. Xwf_dir *
  282. Xdir_load(volp, dirid)
  283. Xwf_vol *volp;
  284. Xlong dirid;
  285. X{
  286. X    wf_dir *dirp;
  287. X    FILE *fp;
  288. X    long magic;
  289. X    int namelen, qlen;
  290. X    wf_file *filep;
  291. X    struct stat statbuf;
  292. X    char path[MAXPATHLEN];
  293. X
  294. X    sprintf(path, "%s/cache/%lx/dir/%lx", cs_topdir, volp->id, dirid);
  295. X    stat(path, &statbuf);
  296. X    if (statbuf.st_size == 0) return NULL;
  297. X    fp = fopen(path, "r");
  298. X    if (fp == NULL) return NULL;
  299. X
  300. X    /* allocate dirp */
  301. X    dirp = dir_alloc(volp);
  302. X    dirp->id = dirid;
  303. X
  304. X    /* read per-directory info */
  305. X    WF_READ(fp, magic);
  306. X    if (magic != WF_DIR_MAGIC) {
  307. X        syslog(LOG_WARNING, "dir magic mismatch");
  308. X        fclose(fp);
  309. X        return NULL;
  310. X    }
  311. X    WF_READ(fp, namelen);
  312. X    dirp->name = malloc(namelen);
  313. X    fread(dirp->name, namelen, 1, fp);
  314. X    WF_READ(fp, dirp->ctime);
  315. X
  316. X    /* read per-file info */
  317. X    WF_READ(fp, qlen);
  318. X    while (qlen--) {
  319. X        filep = file_alloc();
  320. X        dir_addfile(dirp, filep);
  321. X        WF_READ(fp, filep->id);
  322. X        filep->fattr.fileid = filep->id;
  323. X        WF_READ(fp, namelen);
  324. X        filep->name = malloc(namelen);
  325. X        fread(filep->name, namelen, 1, fp);
  326. X        WF_READ(fp, namelen);
  327. X        if (namelen) {
  328. X            filep->link = malloc(namelen);
  329. X            fread(filep->link, namelen, 1, fp);
  330. X        }
  331. X
  332. X        WF_READ(fp, filep->fattr.type);
  333. X        WF_READ(fp, filep->fattr.mode);
  334. X        WF_READ(fp, filep->fattr.nlink);
  335. X        WF_READ(fp, filep->fattr.uid);
  336. X        WF_READ(fp, filep->fattr.gid);
  337. X        WF_READ(fp, filep->fattr.size);
  338. X        WF_READ(fp, filep->fattr.blocksize);
  339. X        WF_READ(fp, filep->fattr.rdev);
  340. X        WF_READ(fp, filep->fattr.blocks);
  341. X        WF_READ(fp, filep->fattr.fsid);
  342. X        WF_READ(fp, filep->crc);
  343. X        WF_READ(fp, filep->fattr.atime.seconds);
  344. X        WF_READ(fp, filep->fattr.atime.useconds);
  345. X        WF_READ(fp, filep->fattr.mtime.seconds);
  346. X        WF_READ(fp, filep->fattr.mtime.useconds);
  347. X        WF_READ(fp, filep->fattr.ctime.seconds);
  348. X        WF_READ(fp, filep->fattr.ctime.useconds);
  349. X    }
  350. X
  351. X    fclose(fp);
  352. X    return dirp;
  353. X}
  354. X
  355. Xvoid
  356. Xdir_save(volp, dirp, olddirp)
  357. Xwf_vol *volp;
  358. Xwf_dir *dirp, *olddirp;
  359. X{
  360. X    FILE *fp;
  361. X    long magic = WF_DIR_MAGIC;
  362. X    int namelen, qlen;
  363. X    wf_file *filep;
  364. X    char path[MAXPATHLEN];
  365. X
  366. X    sprintf(path, "%s/cache/%lx/dir/%lx", cs_topdir, volp->id, dirp->id);
  367. X    mkdirs(path);
  368. X    fp = fopen(path, "w+");
  369. X
  370. X    /* write per-directory info */
  371. X    WF_WRITE(fp, magic);
  372. X    namelen = strlen(dirp->name)+1;
  373. X    WF_WRITE(fp, namelen);
  374. X    fwrite(dirp->name, namelen, 1, fp);
  375. X    WF_WRITE(fp, dirp->ctime);
  376. X
  377. X    /* write per-file info */
  378. X    qlen = q_len(dirp->file);
  379. X    WF_WRITE(fp, qlen);
  380. X    ITER(filep, wf_file, &dirp->file->q) {
  381. X        WF_WRITE(fp, filep->id);
  382. X        namelen = strlen(filep->name)+1;
  383. X        WF_WRITE(fp, namelen);
  384. X        fwrite(filep->name, namelen, 1, fp);
  385. X        if (filep->link) {
  386. X            namelen = strlen(filep->link)+1;
  387. X            WF_WRITE(fp, namelen);
  388. X            fwrite(filep->link, namelen, 1, fp);
  389. X        } else {
  390. X            namelen = 0;
  391. X            WF_WRITE(fp, namelen);
  392. X        }
  393. X
  394. X        WF_WRITE(fp, filep->fattr.type);
  395. X        WF_WRITE(fp, filep->fattr.mode);
  396. X        WF_WRITE(fp, filep->fattr.nlink);
  397. X        WF_WRITE(fp, filep->fattr.uid);
  398. X        WF_WRITE(fp, filep->fattr.gid);
  399. X        WF_WRITE(fp, filep->fattr.size);
  400. X        WF_WRITE(fp, filep->fattr.blocksize);
  401. X        WF_WRITE(fp, filep->fattr.rdev);
  402. X        WF_WRITE(fp, filep->fattr.blocks);
  403. X        WF_WRITE(fp, filep->fattr.fsid);
  404. X        WF_WRITE(fp, filep->crc);
  405. X        WF_WRITE(fp, filep->fattr.atime.seconds);
  406. X        WF_WRITE(fp, filep->fattr.atime.useconds);
  407. X        WF_WRITE(fp, filep->fattr.mtime.seconds);
  408. X        WF_WRITE(fp, filep->fattr.mtime.useconds);
  409. X        WF_WRITE(fp, filep->fattr.ctime.seconds);
  410. X        WF_WRITE(fp, filep->fattr.ctime.useconds);
  411. X    }
  412. X
  413. X    fclose(fp);
  414. X    if (olddirp) {
  415. X        /* reclaim */
  416. X        ITER(filep, wf_file, &olddirp->file->q) {
  417. X            if (filep->fattr.type != NFDIR) continue;
  418. X            if (! strcmp(filep->name, "..")) continue;
  419. X            if (file_findid(dirp, FSID(filep), FID(filep)) == 0) {
  420. X                /* directory was removed at fileserver.
  421. X                 * reflect the change.
  422. X                 */
  423. X                dir_dispose(volp, FID(filep));
  424. X            }
  425. X        }
  426. X    }
  427. X}
  428. X
  429. Xvoid
  430. Xdir_realdir(path, volp, dirp)
  431. Xchar *path;
  432. Xwf_vol *volp;
  433. Xwf_dir *dirp;
  434. X{
  435. X    char *p;
  436. X    char path2[MAXPATHLEN];
  437. X    int fd;
  438. X
  439. X    strcpy(path2, path);
  440. X    p = strrchr(path2, '/');
  441. X    strcpy(p+1, ".realdir");
  442. X    fd = open(path2, O_WRONLY|O_CREAT|O_TRUNC, 0660);
  443. X    if (fd < 0)
  444. X        dlog("dir_realdir: couldn't create file");
  445. X    sprintf(path2, "%s/%s%s", volp->dir, volp->name,
  446. X        dirp ? dirp->name : " (directory)");
  447. X    write(fd, path2, strlen(path2)+1);
  448. X    close(fd);
  449. X}
  450. X
  451. Xvoid
  452. Xdir_dispose(volp, dirid)
  453. Xwf_vol *volp;
  454. Xlong dirid;
  455. X{
  456. X    char path[MAXPATHLEN], path2[MAXPATHLEN];
  457. X
  458. X    sprintf(path, "%s/cache/%lx/dir/%lx",
  459. X        cs_topdir, volp->id, dirid);
  460. X    sprintf(path2, "%s/stale/%s.%d/%lx/dir/%lx",
  461. X        cs_topdir, cs_date, cs_serial, volp->id, dirid);
  462. X    mkdirs(path2);
  463. X    rename(path, path2);
  464. X    sprintf(path, "/bin/mv -f %s/cache/%lx/%lx %s/stale/%s.%d/%lx",
  465. X        cs_topdir, volp->id, dirid,
  466. X        cs_topdir, cs_date, cs_serial, volp->id);
  467. X    unix_command(path);
  468. X#if 0
  469. X    cs_serial++;
  470. X#endif
  471. X}
  472. X
  473. Xvoid
  474. Xdir_inspect(reqp, name)
  475. Xwf_req *reqp;
  476. Xchar *name;
  477. X{
  478. X    int ret;
  479. X    wf_ih ih;
  480. X    int id = reqp->id;
  481. X
  482. X    ret = root_name2ih(name, &ih);
  483. X    if (ret != WF_REP_OK) {
  484. X        req_send(reqp, "513.%03d root_name2ih: error code %d.\n",
  485. X             id, ret);
  486. X        return;
  487. X    }
  488. X    req_send(reqp, "220-%03d dir %s\n", id, name);
  489. X    req_send(reqp, "213-%03d name = %s\n", id, PROT(ih.dirp->name));
  490. X    req_send(reqp, "213-%03d id = %lx\n", id, ih.dirp->id);
  491. X    req_send(reqp, "213-%03d flag = %x\n", id, ih.dirp->flag);
  492. X    req_send(reqp, "213-%03d idle = %d\n", id, ih.dirp->idle);
  493. X    req_send(reqp, "213-%03d ctime = %ld (%20.20s)\n",
  494. X         id, ih.dirp->ctime, ctime(&ih.dirp->ctime)+4);
  495. X    req_send(reqp, "213.%03d n_xfer = %d\n", id, ih.dirp->n_xfer);
  496. X}
  497. X
  498. END_OF_FILE
  499.   if test 10665 -ne `wc -c <'csd/dir.c'`; then
  500.     echo shar: \"'csd/dir.c'\" unpacked with wrong size!
  501.   fi
  502.   # end of 'csd/dir.c'
  503. fi
  504. if test -f 'csd/ftp_list.c' -a "${1}" != "-c" ; then 
  505.   echo shar: Will not clobber existing file \"'csd/ftp_list.c'\"
  506. else
  507.   echo shar: Extracting \"'csd/ftp_list.c'\" \(11734 characters\)
  508.   sed "s/^X//" >'csd/ftp_list.c' <<'END_OF_FILE'
  509. X/* 
  510. X * WorldWide File System
  511. X * Copyright (c) 1992,1993 Youki Kadobayashi
  512. X * Copyright (c) 1992,1993 Osaka University
  513. X * All rights reserved.
  514. X *
  515. X * Permission to use, copy, modify and distribute this software and its
  516. X * documentation is hereby granted, provided that the following conditions
  517. X * are met:
  518. X * 1. Both the copyright notice and this permission notice appear in
  519. X *    all copies of the software, derivative works or modified versions,
  520. X *    and any portions thereof, and that both notices appear in
  521. X *    supporting documentation.
  522. X * 2. All advertising materials mentioning features or use of this software
  523. X *    must display the following acknowledgement:
  524. X *      This product includes software developed by the Osaka University
  525. X *      and its contributors.
  526. X * 3. Neither the name of the University nor the names of its contributors
  527. X *    may be used to endorse or promote products derived from this software
  528. X *    without specific prior written permission.
  529. X *
  530. X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND OSAKA
  531. X * UNIVERSITY DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  532. X * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  533. X *
  534. X * Osaka University requests users of this software to return to
  535. X *
  536. X *  Youki Kadobayashi
  537. X *  Department of Information and Computer Sciences
  538. X *  Osaka University, Toyonaka 560, Osaka, Japan
  539. X *
  540. X * any improvements or extensions that they make and grant Osaka
  541. X * University the rights to redistribute these changes.
  542. X */
  543. X/* NFS over FTP */
  544. Xstatic char *AtFSid = "$Header: ftp_list.c[109.0] Wed Nov 24 03:47:09 1993 youki-k@is.aist-nara.ac.jp saved $";
  545. X
  546. X#include <sys/types.h>
  547. X#include <sys/ioctl.h>        /* for FIONREAD */
  548. X#include <ctype.h>
  549. X#include <string.h>        /* for strchr */
  550. X#include "wfs.h"
  551. X#include "util.h"
  552. X#include "global.h"
  553. X
  554. Xstatic void
  555. Xftp_readdir_lock(c)
  556. Xwf_thrd *c;
  557. X{
  558. X    c->filep->thrdp = c;
  559. X    ++c->dotdotp->n_xfer;
  560. X}
  561. X
  562. Xstatic void
  563. Xftp_readdir_unlock(c)
  564. Xwf_thrd *c;
  565. X{
  566. X    c->filep->thrdp = (wf_thrd *)0;
  567. X    warn_negative(--c->dotdotp->n_xfer);
  568. X    if (c->cp)
  569. X        c->cp->thrdp = (wf_thrd *)0;
  570. X}
  571. X
  572. Xstatic void ftp_readdir_2(), ftp_readdir_3(), ftp_readdir_fail();
  573. Xvoid
  574. Xftp_readdir_miss(c)
  575. Xwf_thrd *c;
  576. X/* in: rqstp, volp, filep, fhp, cookie, count, dotdotp, olddirp */
  577. X/* out: cp, dirp, flag */
  578. X{
  579. X    wf_file *p;
  580. X
  581. X    ftp_readdir_lock(c);
  582. X    if (c->fhp->child_dir > WF_VOL_BASE) {
  583. X        if (c->olddirp) {
  584. X            c->dirp = dir_new(c->child_volp, c->fhp->child_dir,
  585. X                      c->dotdotp->name, "");
  586. X        } else {
  587. X            c->dirp = vol_newroot(c->child_volp);
  588. X        }
  589. X    } else {
  590. X        c->dirp = dir_new(c->child_volp, c->fhp->child_dir,
  591. X                  c->dotdotp->name, c->filep->name);
  592. X    }
  593. X    p = dir_adddir(c->dirp, ".", c->child_volp->id, c->dirp->id);
  594. X    attr_touch(&p->fattr);
  595. X    p = dir_adddir(c->dirp, "..", c->parent_volp->id, c->dotdotp->id);
  596. X    attr_touch(&p->fattr);
  597. X
  598. X    c->cp = vol_getconn(c->child_volp);
  599. X    if (c->cp == (wf_conn *)0) {
  600. X        if ((c->child_volp->flag & WF_VOL_XCONN)
  601. X            || (c->cp = vol_newconn(c->child_volp)) == (wf_conn *)0) {
  602. X            /* exceeded resource limit */
  603. X            ftp_readdir_unlock(c);
  604. X            (*c->reply)(c, WF_ERR_NQUOT);
  605. X            return;
  606. X        }
  607. X        assert(c->cp != (wf_conn *)0);
  608. X        /* new connection needed */
  609. X        sched_task(ftp_readdir_2, c, &c->cp);
  610. X        thrd_watch(c);
  611. X        c->flag |= WF_THREAD_BUSY;
  612. X        ftp_conn_open(c);
  613. X        return;
  614. X    }
  615. X    c->flag |= WF_THREAD_BUSY;
  616. X    ftp_readdir_2(c);
  617. X}
  618. X
  619. Xstatic void
  620. Xftp_readdir_2(c)
  621. Xwf_thrd *c;
  622. X{
  623. X    int ret;
  624. X
  625. X    c->idle = 0;
  626. X    switch (c->step) {
  627. X    case FTPS_CONN_FAIL:
  628. X        ftp_readdir_fail(c);
  629. X        return;
  630. X    case FTPS_PROMPT:
  631. X#ifdef VERBOSE
  632. X        talk(c->client, "listing directory %s", c->dirp->name);
  633. X        dlog("listing directory %s", c->dirp->name);
  634. X#endif
  635. X        c->cp->thrdp = c;
  636. X        c->flag |= WF_THREAD_RISKY;
  637. X        c->give_up = ftp_readdir_fail;
  638. X        c->closure = (void *)c;
  639. X        ret = tcp_send(c->cp->id, "STAT %s/%s%s/\r\n",
  640. X                   c->cp->srv->variant & WF_FTP_FOLLOW ? "-L ": "",
  641. X                   c->cp->info, c->dirp->name);
  642. X        if (cs_ftp_debug) {
  643. X            req_send(cs_ftp_debug, "STAT /%s%s/\r\n",
  644. X                 c->cp->info, c->dirp->name);
  645. X        }
  646. X        if (ret < 0) {
  647. X            ftp_readdir_fail(c);
  648. X            return;
  649. X        }
  650. X        c->step = FTPS_STAT_RECV;
  651. X        so_clear(c->cp->id);
  652. X        so_callback(c->cp->id, ftp_readdir_2, c);
  653. X        return;
  654. X    case FTPS_STAT_RECV:
  655. X        so_clear(c->cp->id);
  656. X        /* now receive listings. */
  657. X        c->step = FTPS_STAT_RECVINIT;
  658. X        sched_task(ftp_readdir_3, c, &c->cp->id);
  659. X        ftp_recv_list(c);
  660. X        return;
  661. X    }
  662. X}
  663. X
  664. X#ifdef TRACE
  665. Xstatic void
  666. Xftp_readdir_trace(c)
  667. Xwf_thrd *c;
  668. X{
  669. X    wf_trace *tracep;
  670. X    tracep = ALLOC(wf_trace);
  671. X    tracep->time = gettime();
  672. X    tracep->volume = c->child_volp->id;
  673. X    tracep->dir = c->dirp->id;
  674. X    tracep->op = WF_OP_READDIR;
  675. X    tracep->hit = WF_CACHE_READY;
  676. X    trace_event(c, tracep);
  677. X}
  678. X#endif
  679. X
  680. Xstatic void
  681. Xftp_readdir_3(c)
  682. Xwf_thrd *c;
  683. X{
  684. X    ftp_readdir_unlock(c);
  685. X    vol_releaseconn(c->child_volp);
  686. X    c->flag &= ~WF_THREAD_BUSY;
  687. X
  688. X#ifdef TRACE
  689. X    ftp_readdir_trace(c);
  690. X#endif
  691. X
  692. X    if (c->flag & WF_THREAD_ERROR) {
  693. X#ifdef VERBOSE
  694. X        talk(c->client, "FTP readdir failed for volume \"%s\" directory \"%s\"",
  695. X             c->child_volp->name, c->dirp->name);
  696. X        dlog("FTP readdir failed for volume \"%s\" directory \"%s\"",
  697. X             c->child_volp->name, c->dirp->name);
  698. X#endif
  699. X        (*c->reply)(c, WF_ERR_IO);
  700. X    } else {
  701. X        wf_file *f;
  702. X
  703. X        f = file_findname(c->dirp, ".");
  704. X        c->filep->fattr.nlink = f->fattr.nlink;
  705. X        dir_save(c->child_volp, c->dirp, c->olddirp);
  706. X        (*c->reply)(c, WF_REP_OK);
  707. X    }
  708. X}
  709. X
  710. Xstatic void
  711. Xftp_readdir_fail(c)
  712. Xwf_thrd *c;
  713. X{
  714. X    wf_conn *cp = c->cp;
  715. X    c->flag |= WF_THREAD_ERROR;
  716. X    ftp_readdir_3(c);
  717. X    conn_shutdown(cp, 2);
  718. X}
  719. X
  720. Xvoid
  721. Xftp_recv_list(c)
  722. Xwf_thrd *c;
  723. X{
  724. X    long navail;
  725. X    int nread;
  726. X    char *q;
  727. X    int ret, optlen;
  728. X
  729. X    c->idle = 0;
  730. X    switch (c->step) {
  731. X    case FTPS_STAT_RECVINIT:
  732. X        /* initialize */
  733. X        so_callback(c->cp->id, ftp_recv_list, c);
  734. X        c->buf = so_getbuf(c->cp->id);
  735. X    case FTPS_STAT_RECVLOOP:
  736. X        c->step = FTPS_STAT_RECVLOOP;
  737. X        ioctl(c->cp->id, FIONREAD, &navail);
  738. X        nread = MIN(navail, NFS_MAXDATA);
  739. X        if (nread == 0) {
  740. X            optlen = sizeof(int);
  741. X            getsockopt(c->cp->id, SOL_SOCKET, SO_ERROR,
  742. X                   &ret, &optlen);
  743. X            if (ret && ret < sys_nerr)
  744. X                dlog("ftp_recv_list: %s", sys_errlist[ret]);
  745. X            c->flag |= WF_THREAD_ERROR;
  746. X            break;
  747. X        }
  748. X        ret = recv(c->cp->id, c->buf, nread, MSG_PEEK);
  749. X        if (ret < 0) {
  750. X            errno_diag();
  751. X            c->flag |= WF_THREAD_ERROR;
  752. X            break;
  753. X        }
  754. X        c->buf[nread] = '\0';
  755. X        if ((q = strrchr(c->buf, '\n')) == NULL) return;
  756. X        nread = q - c->buf + 1;
  757. X        recv(c->cp->id, c->buf, nread, 0);
  758. X        c->cp->stats.bytes_from_server += nread;
  759. X        c->child_volp->stats.bytes_from_server += nread;
  760. X        q[1] = '\0';
  761. X        ret = ftp_parse_list(c->buf, c->child_volp,
  762. X                    c->dirp, c->olddirp);
  763. X        if (ret == 211)
  764. X            break;
  765. X        if (ret > 400) {
  766. X            c->flag |= WF_THREAD_ERROR;
  767. X            break;
  768. X        }
  769. X        return;
  770. X    }
  771. X    so_clear(c->cp->id);
  772. X    so_callback(c->cp->id, ftp_recv_junk, (void *)c->cp->id);
  773. X    wakeup(&c->cp->id);
  774. X}
  775. X
  776. X/* parse "LIST" output */
  777. Xint
  778. Xftp_parse_list(buftop, volp, dirp, olddirp)
  779. Xchar *buftop;
  780. Xwf_vol *volp;
  781. Xwf_dir *dirp, *olddirp;
  782. X{
  783. X    char *p, *bufp = buftop;
  784. X    struct tm tm;
  785. X    int i, status = 0;
  786. X
  787. X    wf_file *f;
  788. X    char *f_name, *f_link;
  789. X    ftype f_type;
  790. X    u_int f_nlink, f_mode, f_uid, f_gid, f_id, f_fsid;
  791. X    long f_size, f_time;
  792. X
  793. X    /* ^[\-ld][\-rwxs]{9} \d+ [^ ]+ [^ ]+ \d+ [a-zA-Z]{3} \d+ (\d\d:\d\d|\d\d\d\d) [^ ]+ */
  794. X    while (1) {
  795. X        if (*bufp == '\0') {
  796. X            return status;
  797. X        }
  798. X        if (strchr("-bcdl", *bufp)) {
  799. X            /* /^[\-bcdl]/ -- file type */
  800. X            f_link = 0, f_mode = 0, f_id = 0;
  801. X            switch (*bufp) {
  802. X            case 'b':
  803. X                f_type = NFBLK;
  804. X                break;
  805. X            case 'c':
  806. X                f_type = NFCHR;
  807. X                break;
  808. X            case 'd':
  809. X                f_type = NFDIR;
  810. X                break;
  811. X            case 'l':
  812. X                f_type = NFLNK;
  813. X                break;
  814. X            case '-':
  815. X                f_type = NFREG;
  816. X                break;
  817. X            default:
  818. X                dlog("ftp_parse_list: unknown file type %c", *bufp);
  819. X                return 550;
  820. X            }
  821. X            ++bufp;
  822. X        } else {
  823. X            if (isdigit(*bufp)) {
  824. X                /* /^\d{3}\s/ -- status */
  825. X                /* ignore /^\d{3}\-/ */
  826. X                if (isspace(bufp[3])) {
  827. X                    status = atoi(bufp);
  828. X                }
  829. X                bufp = strchr(bufp, '\n')+1;
  830. X                continue;
  831. X            }
  832. X            else if (*bufp == 't' && ! strncmp(bufp, "total", 5)) {
  833. X                /* ^total -- total size in kilobytes */
  834. X                bufp = strchr(bufp, '\n')+1;
  835. X                continue;
  836. X            }
  837. X            else {
  838. X                dlog("FTP parse error: \"%32.32s...\"", bufp);
  839. X                return 550;
  840. X            }
  841. X        }
  842. X
  843. X        /* /[\-rwxs]{9}/ -- permission */
  844. X        if (strchr("-rwxs", *bufp)) {
  845. X            for (i = 0; i < 9; ++i) {
  846. X                f_mode <<= 1;
  847. X                if (strchr("rwxs", *bufp))
  848. X                    f_mode += 1;
  849. X                ++bufp;
  850. X            }
  851. X            f_mode &= ~0222;
  852. X            if (f_mode & 0444) f_mode |= 0644;
  853. X            if (f_mode & 0111) f_mode |= 0111;
  854. X        } else {
  855. X            dlog("ftp_parse_list: unknown permission format");
  856. X            return 550;
  857. X        }
  858. X
  859. X        while (isspace(*bufp)) ++bufp;
  860. X        /* /\d+/ -- nlinks */
  861. X        if (isdigit(*bufp)) {
  862. X            f_nlink = atoi(bufp);
  863. X            while (isdigit(*bufp)) ++bufp;
  864. X        } else {
  865. X            dlog("ftp_parse_list: no nlink");
  866. X            return 550;
  867. X        }
  868. X
  869. X        while (isspace(*bufp)) ++bufp;
  870. X        /* /[^ ]+/ -- owner */
  871. X        while (! isspace(*bufp)) ++bufp;
  872. X        f_uid = 0;
  873. X
  874. X        while (isspace(*bufp)) ++bufp;
  875. X        /* /[^ ]+/ -- group */
  876. X        while (! isspace(*bufp)) ++bufp;
  877. X        f_gid = 0;
  878. X
  879. X        while (isspace(*bufp)) ++bufp;
  880. X        /* /\d+/ -- file size */
  881. X        if (isdigit(*bufp)) {
  882. X            f_size = atoi(bufp);
  883. X            while (isdigit(*bufp)) ++bufp;
  884. X        } else {
  885. X            dlog("ftp_parse_list: no size");
  886. X            return 550;
  887. X        }
  888. X
  889. X        bzero(&tm, sizeof (struct tm));
  890. X        while (isspace(*bufp)) ++bufp;
  891. X        /* /[a-zA-Z]{3}/ -- month */
  892. X        if (! isalpha(*bufp)) {
  893. X            dlog("ftp_parse_list: no month");
  894. X            return 550;
  895. X        }
  896. X        switch (bufp[0] + bufp[1] + bufp[2]) {
  897. X        case 0x119:    /* Jan */
  898. X            tm.tm_mon = 0;
  899. X            break;
  900. X        case 0x10d:    /* Feb */
  901. X            tm.tm_mon = 1;
  902. X            break;
  903. X        case 0x120:    /* Mar */
  904. X            tm.tm_mon = 2;
  905. X            break;
  906. X        case 0x123:    /* Apr */
  907. X            tm.tm_mon = 3;
  908. X            break;
  909. X        case 0x127:    /* May */
  910. X            tm.tm_mon = 4;
  911. X            break;
  912. X        case 0x12d:    /* Jun */
  913. X            tm.tm_mon = 5;
  914. X            break;
  915. X        case 0x12b:    /* Jul */
  916. X            tm.tm_mon = 6;
  917. X            break;
  918. X        case 0x11d:    /* Aug */
  919. X            tm.tm_mon = 7;
  920. X            break;
  921. X        case 0x128:    /* Sep */
  922. X            tm.tm_mon = 8;
  923. X            break;
  924. X        case 0x126:    /* Oct */
  925. X            tm.tm_mon = 9;
  926. X            break;
  927. X        case 0x133:    /* Nov */
  928. X            tm.tm_mon = 10;
  929. X            break;
  930. X        case 0x10c:    /* Dec */
  931. X            tm.tm_mon = 11;
  932. X            break;
  933. X        default:
  934. X            dlog("ftp_parse_list: unknown month");
  935. X            return 550;
  936. X        }
  937. X        bufp += 3;
  938. X
  939. X        while (isspace(*bufp)) ++bufp;
  940. X        /* /\d+/ -- day of month */
  941. X        tm.tm_mday = atoi(bufp);
  942. X        while (! isspace(*bufp)) ++bufp;
  943. X
  944. X        while (isspace(*bufp)) ++bufp;
  945. X        /* /(\d\d:\d\d|\d{4})/ -- time or year */
  946. X        if (bufp[2] == ':') {
  947. X            tm.tm_year = cs_year;
  948. X            if (tm.tm_mon > cs_month) {
  949. X                --tm.tm_year;
  950. X            }
  951. X            tm.tm_hour = atoi(bufp);
  952. X            bufp += 3;
  953. X            tm.tm_min = atoi(bufp);
  954. X            bufp += 2;
  955. X        } else {
  956. X            tm.tm_year = atoi(bufp) - 1900;
  957. X            bufp += 4;
  958. X        }
  959. X        f_time = tm2time(&tm);
  960. X
  961. X        while (isspace(*bufp)) ++bufp;
  962. X        /* /[^ ]+/ -- filename */
  963. X        if (f_type != NFLNK) {
  964. X            p = strchr(bufp, '\r');
  965. X            *p = '\0';
  966. X            if (*bufp == '.' && (strcmp(bufp, ".") == 0
  967. X                         || strcmp(bufp, "..") == 0)) {
  968. X                /*
  969. X                 * We do not put "." and ".." onto directory
  970. X                 * chain; update attributes where necessary.
  971. X                 */
  972. X                f = file_findname(dirp, bufp);
  973. X                assert(f != (wf_file *)0);
  974. X                f->fattr.nlink = f_nlink;
  975. X                f->fattr.atime.seconds
  976. X                    = f->fattr.mtime.seconds
  977. X                    = f->fattr.ctime.seconds = f_time;
  978. X                bufp = p + 2;        /* skip \r\n */
  979. X                continue;
  980. X            }
  981. X            f_name = strdup(bufp);
  982. X            if (f_type == NFDIR) {
  983. X                if (olddirp &&
  984. X                    (f = file_findname(olddirp, f_name))) {
  985. X                    f_id = f->id;
  986. X                } else {
  987. X                    f_id = vol_allocid(volp);
  988. X                }
  989. X            }
  990. X            *p = '\r';
  991. X        } else {
  992. X            p = bufp;
  993. X            while (p = strchr(p, '-')) {
  994. X                if (*++p == '>') break;
  995. X            }
  996. X            if (!p) {
  997. X                dlog("symlink botch");
  998. X                return 550;
  999. X            }
  1000. X            *(p-2) = '\0';
  1001. X            f_name = strdup(bufp);
  1002. X            *(p-2) = ' ';
  1003. X            bufp = p+2;
  1004. X            p = strchr(bufp, '\r');    /* assuming \r\n */
  1005. X            *p = '\0';
  1006. X            f_link = strdup(bufp);
  1007. X            *p = '\r';
  1008. X        }
  1009. X        f_fsid = volp->id;
  1010. X        f = file_new(f_name, f_link, f_type, f_nlink, f_mode,
  1011. X             f_uid, f_gid, f_size, f_time, f_id, f_fsid);
  1012. X        dir_addfile(dirp, f);
  1013. X        bufp = strchr(bufp, '\n')+1;
  1014. X    }
  1015. X}
  1016. X
  1017. END_OF_FILE
  1018.   if test 11734 -ne `wc -c <'csd/ftp_list.c'`; then
  1019.     echo shar: \"'csd/ftp_list.c'\" unpacked with wrong size!
  1020.   fi
  1021.   # end of 'csd/ftp_list.c'
  1022. fi
  1023. if test -f 'csd/root.c' -a "${1}" != "-c" ; then 
  1024.   echo shar: Will not clobber existing file \"'csd/root.c'\"
  1025. else
  1026.   echo shar: Extracting \"'csd/root.c'\" \(12637 characters\)
  1027.   sed "s/^X//" >'csd/root.c' <<'END_OF_FILE'
  1028. X/* 
  1029. X * WorldWide File System
  1030. X * Copyright (c) 1992,1993 Youki Kadobayashi
  1031. X * Copyright (c) 1992,1993 Osaka University
  1032. X * All rights reserved.
  1033. X *
  1034. X * Permission to use, copy, modify and distribute this software and its
  1035. X * documentation is hereby granted, provided that the following conditions
  1036. X * are met:
  1037. X * 1. Both the copyright notice and this permission notice appear in
  1038. X *    all copies of the software, derivative works or modified versions,
  1039. X *    and any portions thereof, and that both notices appear in
  1040. X *    supporting documentation.
  1041. X * 2. All advertising materials mentioning features or use of this software
  1042. X *    must display the following acknowledgement:
  1043. X *      This product includes software developed by the Osaka University
  1044. X *      and its contributors.
  1045. X * 3. Neither the name of the University nor the names of its contributors
  1046. X *    may be used to endorse or promote products derived from this software
  1047. X *    without specific prior written permission.
  1048. X *
  1049. X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND OSAKA
  1050. X * UNIVERSITY DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  1051. X * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  1052. X *
  1053. X * Osaka University requests users of this software to return to
  1054. X *
  1055. X *  Youki Kadobayashi
  1056. X *  Department of Information and Computer Sciences
  1057. X *  Osaka University, Toyonaka 560, Osaka, Japan
  1058. X *
  1059. X * any improvements or extensions that they make and grant Osaka
  1060. X * University the rights to redistribute these changes.
  1061. X */
  1062. X/* root of the world view */
  1063. Xstatic char *AtFSid = "$Header: root.c[109.3] Thu Dec 16 20:39:22 1993 youki-k@is.aist-nara.ac.jp saved $";
  1064. X
  1065. X#include <sys/types.h>
  1066. X#ifdef _POSIX_SOURCE
  1067. X#include <dirent.h>
  1068. X#define    DIRENT    struct dirent
  1069. X#else
  1070. X#include <sys/dir.h>
  1071. X#define    DIRENT    struct direct
  1072. X#endif
  1073. X
  1074. X#include <sys/stat.h>
  1075. X#include <fcntl.h>        /* for O_WRONLY etc. */
  1076. X#include <string.h>        /* for strchr */
  1077. X#include "wfs.h"
  1078. X#include "util.h"
  1079. X#include "global.h"
  1080. X
  1081. Xvoid root_getattr_miss(), root_lookup_miss(), root_read_miss(), root_getuda();
  1082. X
  1083. Xwf_proto proto_root = {
  1084. X    "root", cmfs_getattr, root_getattr_miss,
  1085. X    cmfs_lookup, root_lookup_miss, cmfs_readlink,
  1086. X    cmfs_read, root_read_miss, cmfs_readdir, err_readdir_miss,
  1087. X    root_getuda, err_keepalive, err_close, err_shutdown, 0
  1088. X};
  1089. X
  1090. X/*
  1091. X * ID mappings are somewhat tricky:
  1092. X * parent_dir == child_dir == WF_ROOT_DIR_ID
  1093. X */
  1094. X
  1095. Xwf_vol    *root_vol;
  1096. Xwf_dir    *root_dir;
  1097. Xstatic wf_file    *root_file;
  1098. Xstatic fattr    *root_fattr;
  1099. X
  1100. X/* general functions, not bound to NFS, goes here */
  1101. X
  1102. Xstatic void
  1103. Xroot_load(volp, dotdotp)
  1104. Xwf_vol *volp;
  1105. Xwf_dir *dotdotp;
  1106. X{
  1107. X    DIR *dp;
  1108. X    struct direct *p;
  1109. X    struct stat statbuf;
  1110. X    long dirid;
  1111. X    wf_dir *dirp;
  1112. X    wf_file *filep, *f;
  1113. X    char path[MAXPATHLEN], path2[MAXPATHLEN];
  1114. X
  1115. X    vol_destroyid(volp);        /* clean up bitmap first */
  1116. X    sprintf(path, "%s/vol/%s", cs_topdir, volp->name);
  1117. X    dp = opendir(path);
  1118. X    while (p = readdir(dp)) {
  1119. X        if (p->d_name[0] == '.')
  1120. X            continue;    /* ignore "." and ".." */
  1121. X        sprintf(path2, "%s/vol/%s/%s",
  1122. X            cs_topdir, volp->name, p->d_name);
  1123. X        stat(path2, &statbuf);
  1124. X        if (statbuf.st_mode & S_IFDIR) {
  1125. X            dirid = vol_allocid(volp) + WF_GLUE_BASE;
  1126. X            dirp = dir_new(volp, dirid, "/", p->d_name);
  1127. X            f = dir_adddir(dirp, ".", volp->id, dirid);
  1128. X            attr_touch(&f->fattr);
  1129. X            f = dir_adddir(dirp, "..", volp->id, dotdotp->id);
  1130. X            attr_touch(&f->fattr);
  1131. X            dirp->flag |= WF_DIR_WIREDDOWN;
  1132. X            filep = file_newvol(p->d_name);
  1133. X            FSID(filep) = volp->id;
  1134. X            FID(filep) = filep->fattr.fileid = dirid;
  1135. X            attr_touch(&filep->fattr);
  1136. X            dir_addfile(dotdotp, filep);
  1137. X
  1138. X            /*
  1139. X             * insert index file
  1140. X             */
  1141. X            filep = file_new("INDEX", 0, NFREG, 1, 0644, 0, 0,
  1142. X                     0, now, 0, volp->id);
  1143. X            filep->flag |= WF_FILE_MUTABLE;
  1144. X            dir_addfile(dirp, filep);
  1145. X        }
  1146. X    }
  1147. X    closedir(dp);
  1148. X}
  1149. X
  1150. Xvoid
  1151. Xroot_start()
  1152. X{
  1153. X    wf_vol *volp;
  1154. X    wf_dir *dirp;
  1155. X    wf_file *filep;
  1156. X    char path[MAXPATHLEN];
  1157. X
  1158. X    /*
  1159. X     * create root volume
  1160. X     */
  1161. X    root_vol = volp = vol_alloc();
  1162. X    volp->id = WF_ROOT_VOL_ID;
  1163. X    volp->name = ".";            /* name2ih need it */
  1164. X    volp->dir = "";                /* name2ih need it */
  1165. X    /*
  1166. X     * Bypass file caching mechanism
  1167. X     * for files directly placed in the root volume, such as INDEX.
  1168. X     */
  1169. X    volp->flag |= WF_VOL_DIRECTFILE;
  1170. X    sprintf(path, "%s/vol", cs_topdir);
  1171. X    volp->topdir = strdup(path);
  1172. X    /*
  1173. X     * create root directory
  1174. X     */
  1175. X    root_dir = dirp = dir_new(volp, WF_ROOT_DIR_ID, 0, 0);
  1176. X    dir_adddir(dirp, ".", WF_ROOT_VOL_ID, WF_ROOT_DIR_ID);
  1177. X    dir_adddir(dirp, "..", WF_ROOT_VOL_ID, WF_ROOT_DIR_ID);
  1178. X
  1179. X    /*
  1180. X     * create root node
  1181. X     */
  1182. X    root_file = file_findid(dirp, WF_ROOT_VOL_ID, WF_ROOT_DIR_ID);
  1183. X    root_fattr = &root_file->fattr;
  1184. X    attr_touch(root_fattr);
  1185. X    dirp->flag |= WF_DIR_WIREDDOWN;
  1186. X
  1187. X    /*
  1188. X     * create subdirectories
  1189. X     */
  1190. X    root_load(root_vol, root_dir);
  1191. X
  1192. X    /*
  1193. X     * insert index file
  1194. X     */
  1195. X    filep = file_new("INDEX", 0, NFREG, 1, 0644, 0, 0,
  1196. X             0, now, 0, volp->id);
  1197. X    filep->flag |= WF_FILE_MUTABLE;
  1198. X    dir_addfile(dirp, filep);
  1199. X}
  1200. X
  1201. Xwf_file *
  1202. Xroot_attach(dirp, name)
  1203. Xwf_dir *dirp;
  1204. Xchar *name;
  1205. X{
  1206. X    /*
  1207. X     * Attach a volume to the specified directory.
  1208. X     */
  1209. X    wf_vol *volp;
  1210. X    wf_file *filep;
  1211. X    int ret;
  1212. X    char *p, *volume;
  1213. X
  1214. X    p = strrchr(name, '/');
  1215. X    volume = p ? p+1 : name;
  1216. X    volp = vol_findname(dirp->name, volume);
  1217. X    if (volp == (wf_vol *)0)
  1218. X        return (wf_file *)0;
  1219. X
  1220. X    filep = file_newvol(volume);
  1221. X    FSID(filep) = volp->id;
  1222. X    FID(filep) = filep->fattr.fileid = volp->id + WF_VOL_BASE;
  1223. X    dir_addfile(dirp, filep);
  1224. X    return filep;
  1225. X}
  1226. X
  1227. Xint
  1228. Xroot_deletevol(name)
  1229. Xchar *name;
  1230. X{
  1231. X    /*
  1232. X     * Delete a volume from the root namespace.
  1233. X     */
  1234. X    wf_file *filep;
  1235. X    wf_ih ih;
  1236. X    int ret;
  1237. X
  1238. X    ret = root_name2ih(name, &ih);
  1239. X    if (ret != WF_REP_OK)
  1240. X        return ret;
  1241. X    if (ih.filep) {
  1242. X        dir_deletefile(ih.filep);
  1243. X        file_uncache(ih.dirp);
  1244. X        file_free(ih.filep);
  1245. X    }
  1246. X    vol_free(ih.child_volp);
  1247. X    return WF_REP_OK;
  1248. X}
  1249. X
  1250. Xint
  1251. Xroot_fhn2ih(pname, ihp)
  1252. Xchar *pname;
  1253. Xwf_ih *ihp;    /* result */
  1254. X{
  1255. X    /* convert "+fh/name" into internal handle */
  1256. X    char *p = pname, *q;
  1257. X    long pvid, pfid, cvid, cfid;
  1258. X
  1259. X    /*
  1260. X     * see bfs.c:fh_read() for ASCII representation of fh
  1261. X     */
  1262. X    pvid = strtol(++p, &q, 16);
  1263. X    if (p == q)
  1264. X        return WF_ERR_STALE;    /* stale ascii file handle */
  1265. X
  1266. X    pfid = strtol(p = ++q, &q, 16);
  1267. X    if (p == q)
  1268. X        return WF_ERR_STALE;    /* stale ascii file handle */
  1269. X
  1270. X    cvid = strtol(p = ++q, &q, 16);
  1271. X    ihp->parent_volp = vol_findid(cvid);
  1272. X    if (! ihp->parent_volp || p == q)
  1273. X        return WF_ERR_STALE;    /* stale ascii file handle */
  1274. X
  1275. X    cfid = strtol(p = ++q, &q, 16);
  1276. X    ihp->dirp = dir_findcache(ihp->parent_volp, cfid);
  1277. X    if (p == q)
  1278. X        return WF_ERR_STALE;    /* stale ascii file handle */
  1279. X    if (! ihp->dirp || (ihp->dirp->flag & WF_DIR_OBSOLETE)) {
  1280. X        /* Directory not cached. This is likely to happen
  1281. X         * when only /a is cached upon request "/a/b/c".
  1282. X         * Forcibly ignore the following path components...
  1283. X         */
  1284. X        ihp->child_volp = ihp->parent_volp;
  1285. X        ihp->dirp = dir_findcache(ihp->parent_volp, pfid);
  1286. X        if (! ihp->dirp)
  1287. X            return WF_ERR_STALE;
  1288. X        ihp->filep = file_findid(ihp->dirp, ihp->child_volp->id, cfid);
  1289. X        if (! ihp->filep)
  1290. X            return WF_ERR_STALE;
  1291. X        return WF_REP_WAIT;
  1292. X    }
  1293. X
  1294. X    if (*q != '/')
  1295. X        return WF_ERR_NOTDIR;
  1296. X    if (*++q == '\0') q = ".";    /* "fh/" --> "fh/." */
  1297. X    ihp->filep = file_findname(ihp->dirp, q);
  1298. X    if (! ihp->filep) {
  1299. X        if (ihp->dirp->flag & WF_DIR_WIREDDOWN) {
  1300. X            /* XXX assuming WF_DIR_WIREDDOWN = root/glue */
  1301. X            /*
  1302. X             * looking at invisible volumes...
  1303. X             * let's make it visible.
  1304. X             */
  1305. X            ihp->filep = root_attach(ihp->dirp, q);
  1306. X        }
  1307. X        if (! ihp->filep) {
  1308. X            return WF_ERR_NOENT;
  1309. X        }
  1310. X    }
  1311. X    ihp->child_volp = vol_findid(FSID(ihp->filep));
  1312. X    if (! ihp->child_volp) {
  1313. X        return WF_ERR_NOENT;
  1314. X    }
  1315. X    return WF_REP_OK;
  1316. X}
  1317. X
  1318. Xint
  1319. Xroot_name2ih(pname, ihp)
  1320. Xchar *pname;
  1321. Xwf_ih *ihp;    /* result */
  1322. X{
  1323. X    char *p, *q = pname;
  1324. X    wf_vol *volp = root_vol;
  1325. X    wf_dir *dirp = root_dir, *dirp2 = root_dir;
  1326. X    wf_file *filep = root_file;
  1327. X    long prev_vol = volp->id;
  1328. X    int ret = WF_REP_OK;
  1329. X
  1330. X    ihp->parent_volp = volp;
  1331. X    while (q) {
  1332. X        p = q;
  1333. X        /* end of path? */
  1334. X        while (*p == '/') ++p;
  1335. X        if (*p == '\0') break;
  1336. X        dirp = dirp2;
  1337. X        ihp->parent_volp = volp;
  1338. X        /* lookup a path component */
  1339. X        q = strchr(p, '/');
  1340. X        if (q) *q = '\0';
  1341. X        filep = file_findname(dirp, p);
  1342. X        if (q) *q = '/';
  1343. X        if (!filep) {
  1344. X            if (dirp->flag & WF_DIR_WIREDDOWN) {
  1345. X                /* XXX assuming WF_DIR_WIREDDOWN = root/glue */
  1346. X                /*
  1347. X                 * looking at invisible volumes...
  1348. X                 * let's make it visible.
  1349. X                 */
  1350. X                if (q) *q = '\0';
  1351. X                filep = root_attach(dirp, p);
  1352. X                if (q) *q = '/';
  1353. X            }
  1354. X            if (!filep) {
  1355. X                ret = WF_ERR_NOENT;
  1356. X                goto fin;
  1357. X            }
  1358. X        }
  1359. X        if (filep->fattr.type == NFREG) break;
  1360. X        if (prev_vol != FSID(filep)) {
  1361. X            volp = vol_findid(FSID(filep));
  1362. X            if (!volp) {
  1363. X                dlog("root_name2ih: illegal fsid");
  1364. X                ret = WF_ERR_STALE;
  1365. X                goto fin;
  1366. X            }
  1367. X            prev_vol = volp->id;
  1368. X        }
  1369. X        dirp2 = dir_findcache(volp, filep->id);
  1370. X        if (!dirp2 || (dirp2->flag & WF_DIR_OBSOLETE)) {
  1371. X            /* Directory not cached. This is likely to happen
  1372. X             * when only /a is cached upon request "/a/b/c".
  1373. X             * Forcibly ignore the following path components...
  1374. X             */
  1375. X            ret = WF_REP_WAIT;
  1376. X            goto fin;
  1377. X        }
  1378. X    }
  1379. X fin:
  1380. X    ihp->child_volp = volp;
  1381. X    ihp->dirp = dirp;
  1382. X    ihp->filep = filep;
  1383. X    return ret;
  1384. X}
  1385. X
  1386. Xvoid
  1387. Xih2fh(ihp, fhp)
  1388. Xwf_ih *ihp;
  1389. Xwf_fh *fhp;    /* result */
  1390. X{
  1391. X    fhp->world_id = cs_world;
  1392. X    fhp->parent_vol = ihp->parent_volp->id;
  1393. X    fhp->dir_id = ihp->dirp->id;
  1394. X    fhp->child_vol = ihp->child_volp->id;
  1395. X    fhp->file_id = ihp->filep->id;
  1396. X}
  1397. X
  1398. Xint
  1399. Xroot_name2fh(pname, fhp)
  1400. Xchar *pname;
  1401. Xwf_fh *fhp;    /* result */
  1402. X{
  1403. X    int ret;
  1404. X    wf_ih ih;
  1405. X
  1406. X    ret = root_name2ih(pname, &ih);
  1407. X    if (ret == WF_REP_OK) {
  1408. X        ih2fh(&ih, fhp);
  1409. X    }
  1410. X    return ret;
  1411. X}
  1412. X
  1413. Xvoid
  1414. Xroot_inspect(reqp, arg)
  1415. Xwf_req *reqp;
  1416. Xchar *arg;
  1417. X{
  1418. X    int ret;
  1419. X    wf_fh fh;
  1420. X    int id = reqp->id;
  1421. X
  1422. X    ret = root_name2fh(arg, &fh);
  1423. X    if (ret != WF_REP_OK) {
  1424. X        req_send(reqp, "513.%03d root_name2fh: error code %d.\n",
  1425. X             id, ret);
  1426. X        return;
  1427. X    }
  1428. X    req_send(reqp, "220-%03d fhd %s\n", id, arg);
  1429. X    req_send(reqp, "213-%03d world_id = %lx\n", id, fh.world_id);
  1430. X    req_send(reqp, "213-%03d parent_vol = %lx\n", id, fh.parent_vol);
  1431. X    req_send(reqp, "213-%03d dir_id = %lx\n", id, fh.dir_id);
  1432. X    req_send(reqp, "213-%03d child_vol = %lx\n", id, fh.child_vol);
  1433. X    req_send(reqp, "213.%03d file_id = %lx\n", id, fh.file_id);
  1434. X}
  1435. X
  1436. X/* NFS-delegate functions */
  1437. X
  1438. Xvoid
  1439. Xroot_getattr_miss(c)
  1440. Xwf_thrd *c;    /* volp, dirp, filep */
  1441. X{
  1442. X    fattr *attrp = &c->filep->fattr;
  1443. X    struct stat statbuf;
  1444. X    char path[MAXPATHLEN];
  1445. X
  1446. X    file_getpath(path, c->child_volp, c->dirp, c->filep);
  1447. X    if (stat(path, &statbuf) == 0) {
  1448. X        attrp->nlink = statbuf.st_nlink;
  1449. X        attrp->size = statbuf.st_size;
  1450. X        /* sgi doesn't have st_blocks, so... */
  1451. X        attrp->blocks = (statbuf.st_size + 1024) >> 10;
  1452. X        attrp->atime.seconds = statbuf.st_atime;
  1453. X        attrp->mtime.seconds = statbuf.st_mtime;
  1454. X        attrp->ctime.seconds = statbuf.st_ctime;
  1455. X    } else {
  1456. X        /* File does not exist; fake it. */
  1457. X        attrp->nlink = 1;
  1458. X        attrp->size = 0;
  1459. X        /* sgi doesn't have st_blocks, so... */
  1460. X        attrp->blocks = 1;
  1461. X        attrp->atime.seconds = attrp->mtime.seconds = 
  1462. X            attrp->ctime.seconds = now;
  1463. X    }
  1464. X}
  1465. X
  1466. Xvoid
  1467. Xroot_read_miss(c)
  1468. Xwf_thrd *c;
  1469. X/* in: rqstp, volp, offset, count, totalcount, dirp, filep */
  1470. X{
  1471. X    FILE *fp;
  1472. X    char path[MAXPATHLEN];
  1473. X
  1474. X    if (strcmp(c->filep->name, "INDEX") == 0) {
  1475. X        /* INDEX does not exist; generate it on the fly... */
  1476. X        file_getpath(path, c->child_volp, c->dirp, c->filep);
  1477. X        fp = fopen(path, "w");
  1478. X        if (! fp) {
  1479. X            dlog("Could not open %s for writing: errno=%d",
  1480. X                 path, errno);
  1481. X            (*c->reply)(c, WF_ERR_IO);
  1482. X            return;
  1483. X        }
  1484. X        fprintf(fp,
  1485. X            "Sorry, but INDEX cannot be generated automatically.\n\
  1486. XPlease e-mail your WWFS Administrator <wwfs@%s.%s>\n\
  1487. Xand ask him/her for help.\n\
  1488. X\n\
  1489. XThank you.\n\
  1490. X        \"csd\" running on %s.%s\n\
  1491. X        WorldWide File System\n\
  1492. X        A research product of Osaka University, Japan\n",
  1493. X            cs_hostname, cs_domain,
  1494. X            cs_hostname, cs_domain);
  1495. X        fclose(fp);
  1496. X        /* try to read me again... */
  1497. X        (*c->reply)(c, WF_ERR_STALE);
  1498. X    } else {
  1499. X        /* strange.. real file should not exist except INDEX */
  1500. X        (*c->reply)(c, WF_ERR_IO);
  1501. X    }
  1502. X}
  1503. X
  1504. Xvoid
  1505. Xroot_lookup_miss(c)
  1506. Xwf_thrd *c;    /* rqstp, volp, fhp, fname, dotdotp */
  1507. X{
  1508. X    wf_vol        *subvolp;
  1509. X    wf_fh        *resfhp;
  1510. X
  1511. X    c->parent_volp = c->child_volp;
  1512. X    c->child_volp = vol_findname(c->dotdotp->name, c->fname);
  1513. X    if (c->child_volp == NULL) {
  1514. X        (*c->reply)(c, WF_ERR_NOENT);
  1515. X        return;
  1516. X    }
  1517. X
  1518. X    /* update root fattr */
  1519. X    ++root_fattr->nlink;
  1520. X    attr_touch(root_fattr);
  1521. X
  1522. X    /* filehandle response */
  1523. X    resfhp = c->resfhp = CLONE(c->fhp);
  1524. X    c->resfhp->world_id = cs_world;
  1525. X    c->resfhp->parent_vol = c->parent_volp->id;
  1526. X    c->resfhp->parent_dir = c->fhp->child_dir;
  1527. X    c->resfhp->child_vol = c->child_volp->id;
  1528. X    c->resfhp->child_dir = c->child_volp->id + WF_VOL_BASE;
  1529. X    /* make it visible */
  1530. X    c->filep = file_newvol(c->fname);
  1531. X    FSID(c->filep) = c->child_volp->id;
  1532. X    FID(c->filep) = c->filep->fattr.fileid = c->resfhp->file_id;
  1533. X    dir_addfile(c->dotdotp, c->filep);
  1534. X    (*c->reply)(c, WF_REP_OK);
  1535. X    FREE(resfhp);
  1536. X}
  1537. X
  1538. Xvoid
  1539. Xroot_getuda()
  1540. X{
  1541. X    /* XXX not implemented yet */
  1542. X}
  1543. END_OF_FILE
  1544.   if test 12637 -ne `wc -c <'csd/root.c'`; then
  1545.     echo shar: \"'csd/root.c'\" unpacked with wrong size!
  1546.   fi
  1547.   # end of 'csd/root.c'
  1548. fi
  1549. if test -f 'csd/uip.c' -a "${1}" != "-c" ; then 
  1550.   echo shar: Will not clobber existing file \"'csd/uip.c'\"
  1551. else
  1552.   echo shar: Extracting \"'csd/uip.c'\" \(12592 characters\)
  1553.   sed "s/^X//" >'csd/uip.c' <<'END_OF_FILE'
  1554. X/* 
  1555. X * WorldWide File System
  1556. X * Copyright (c) 1992,1993 Youki Kadobayashi
  1557. X * Copyright (c) 1992,1993 Osaka University
  1558. X * All rights reserved.
  1559. X *
  1560. X * Permission to use, copy, modify and distribute this software and its
  1561. X * documentation is hereby granted, provided that the following conditions
  1562. X * are met:
  1563. X * 1. Both the copyright notice and this permission notice appear in
  1564. X *    all copies of the software, derivative works or modified versions,
  1565. X *    and any portions thereof, and that both notices appear in
  1566. X *    supporting documentation.
  1567. X * 2. All advertising materials mentioning features or use of this software
  1568. X *    must display the following acknowledgement:
  1569. X *      This product includes software developed by the Osaka University
  1570. X *      and its contributors.
  1571. X * 3. Neither the name of the University nor the names of its contributors
  1572. X *    may be used to endorse or promote products derived from this software
  1573. X *    without specific prior written permission.
  1574. X *
  1575. X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND OSAKA
  1576. X * UNIVERSITY DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  1577. X * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  1578. X *
  1579. X * Osaka University requests users of this software to return to
  1580. X *
  1581. X *  Youki Kadobayashi
  1582. X *  Department of Information and Computer Sciences
  1583. X *  Osaka University, Toyonaka 560, Osaka, Japan
  1584. X *
  1585. X * any improvements or extensions that they make and grant Osaka
  1586. X * University the rights to redistribute these changes.
  1587. X */
  1588. X/*
  1589. X * UIP: WWFS User Interface Protocol.
  1590. X * Both UIP/UDP and UIP/TCP are implemented for ease of use from variety
  1591. X * of programming languages.
  1592. X */
  1593. Xstatic char *AtFSid = "$Header: uip.c[109.1] Thu Dec 16 20:39:25 1993 youki-k@is.aist-nara.ac.jp saved $";
  1594. X
  1595. X#include <sys/ioctl.h>        /* for FIONREAD */
  1596. X#include <ctype.h>
  1597. X#include <string.h>        /* for strchr */
  1598. X#include "wfs.h"
  1599. X#include "global.h"
  1600. X#include "util.h"
  1601. X
  1602. Xstatic wf_req *
  1603. Xuip_alloc()
  1604. X{
  1605. X    wf_req *p;
  1606. X
  1607. X    p = ALLOC(wf_req);
  1608. X    return p;
  1609. X}
  1610. X
  1611. Xstatic void
  1612. Xuip_free(p)
  1613. Xwf_req *p;
  1614. X{
  1615. X    FREE(p);
  1616. X}
  1617. X
  1618. Xint
  1619. Xuip_id()
  1620. X{
  1621. X    static int id;
  1622. X    if (++id < 0)
  1623. X        id = 0;
  1624. X    return id;
  1625. X}
  1626. X
  1627. Xstatic void
  1628. Xuip_emsg(reqp, buf)
  1629. Xwf_req *reqp;
  1630. Xchar *buf;
  1631. X{
  1632. X    if (strncmp(buf, "progress", 8) == 0) {
  1633. X    }
  1634. X    else if (strncmp(buf, "block", 5) == 0) {
  1635. X    }
  1636. X    else if (strncmp(buf, "ftptrace", 8) == 0) {
  1637. X        cs_ftp_debug = reqp;    /* only one for now */
  1638. X    }
  1639. X    else {
  1640. X        req_send(reqp, "520-%03d opt %s\n", reqp->id, buf);
  1641. X        req_send(reqp, "513.%03d Unknown subcommand.\n", reqp->id);
  1642. X    }
  1643. X}
  1644. X
  1645. Xstatic void
  1646. Xuip_dmsg(reqp, buf)
  1647. Xwf_req *reqp;
  1648. Xchar *buf;
  1649. X{
  1650. X}
  1651. X
  1652. Xstatic void
  1653. Xuip_diag(reqp, buf)
  1654. Xwf_req *reqp;
  1655. Xchar *buf;
  1656. X{
  1657. X#ifdef DEBUG_MALLOC
  1658. X    static unsigned long hist1, hist2;
  1659. X#endif
  1660. X
  1661. X    if (strncmp(buf, "thread", 6) == 0) {
  1662. X        thrd_inspect(reqp);
  1663. X    }
  1664. X    else if (strncmp(buf, "connection", 10) == 0) {
  1665. X        conn_inspect(reqp);
  1666. X    }
  1667. X    else if (strncmp(buf, "file", 4) == 0) {
  1668. X        file_inspect(reqp, buf + 5);
  1669. X    }
  1670. X    else if (strncmp(buf, "dir", 3) == 0) {
  1671. X        dir_inspect(reqp, buf + 4);
  1672. X    }
  1673. X    else if (strncmp(buf, "vol", 3) == 0) {
  1674. X        vol_inspect(reqp, buf + 4);
  1675. X    }
  1676. X    else if (strncmp(buf, "fh", 2) == 0) {
  1677. X        root_inspect(reqp, buf+3);
  1678. X    }
  1679. X#ifdef DEBUG_MALLOC
  1680. X    else if (strncmp(buf, "mallocdump", 10) == 0) {
  1681. X        malloc_dump(reqp->so);
  1682. X    }
  1683. X    else if (strncmp(buf, "malloclist", 10) == 0) {
  1684. X        malloc_inuse(&hist2);
  1685. X        malloc_list(reqp->so, hist1, hist2);
  1686. X    }
  1687. X    else if (strncmp(buf, "mallocfrom", 10) == 0) {
  1688. X        malloc_inuse(&hist1);
  1689. X    }
  1690. X#endif
  1691. X    else {
  1692. X        req_send(reqp, "520-%03d opt %s\n", reqp->id, buf);
  1693. X        req_send(reqp, "513.%03d Unknown subcommand.\n", reqp->id);
  1694. X    }
  1695. X}
  1696. X
  1697. Xstatic void
  1698. Xuip_rtoc(reqp, arg)
  1699. Xwf_req *reqp;
  1700. Xchar *arg;
  1701. X{
  1702. X    int ret;
  1703. X    wf_ih ih;
  1704. X    char path[MAXPATHLEN];
  1705. X
  1706. X    if (strlen(arg) < 5) {
  1707. X        req_send(reqp, "520-%03d cmd RTOC %s\n", reqp->id, arg);
  1708. X        req_send(reqp, "513.%03d Invalid argument.\n", reqp->id);
  1709. X    }
  1710. X    ret = root_name2ih(arg + 4, &ih);
  1711. X    if (ret != WF_REP_OK) {
  1712. X        req_send(reqp, "520-%03d %s\n", reqp->id, arg);
  1713. X        req_send(reqp, "510.%03d root_name2ih: error code %d.\n",
  1714. X             reqp->id, ret);    /* XXX */
  1715. X        return;
  1716. X    }
  1717. X    if (strncmp(arg, "dir", 3) == 0) {
  1718. X        req_send(reqp, "220.%03d c_p %s/cache/%lx/dir/%lx\n",
  1719. X             reqp->id, cs_topdir, ih.child_volp->id, ih.filep->id);
  1720. X    }
  1721. X    else if (strncmp(arg, "fil", 3) == 0) {
  1722. X        file_getpath(path, ih.child_volp, ih.dirp, ih.filep);
  1723. X        req_send(reqp, "220.%03d c_p %s\n", reqp->id, path);
  1724. X    }
  1725. X    else {
  1726. X        req_send(reqp, "520-%03d opt %s\n", reqp->id, arg);
  1727. X        req_send(reqp, "513.%03d Unknown subcommand.\n", reqp->id);
  1728. X    }
  1729. X}
  1730. X
  1731. Xstatic void
  1732. Xuip_retr_done(c, status)
  1733. Xwf_thrd *c;
  1734. Xint status;
  1735. X{
  1736. X    /* UIP connection might have dropped, but it's harmless since
  1737. X     * session ID is guaranteed to be unique and wf_thrd has "deepcopy"
  1738. X     * of necessary member variables.
  1739. X     */
  1740. X
  1741. X    switch (status) {
  1742. X    case WF_REP_OK:
  1743. X        req_send(&c->req, "210.%03d Transfer complete.\n", c->req.id);
  1744. X        break;
  1745. X    case WF_REP_WAIT:
  1746. X        req_send(&c->req, "210 %03d Transfer ongoing.\n", c->req.id);
  1747. X        break;
  1748. X    default:
  1749. X        req_send(&c->req, "510.%03d Transfer failed, error=%d\n",
  1750. X             c->req.id, status);    /* XXX */
  1751. X        break;
  1752. X    }
  1753. X    if (! (c->flag & WF_THREAD_BUSY)) {
  1754. X        FREE(c->fhp);
  1755. X        thrd_free(c);
  1756. X    }
  1757. X}
  1758. X
  1759. Xstatic void
  1760. Xuip_retr_loop(c, status)
  1761. Xwf_thrd *c;
  1762. Xint status;
  1763. X{
  1764. X    if (status == WF_REP_OK) {
  1765. X        status = uip_retr_2(&c->req, c->pathname);
  1766. X        if (status != WF_REP_WAIT && c->pathname)
  1767. X            free(c->pathname);
  1768. X        FREE(c->fhp);
  1769. X        thrd_free(c);
  1770. X    } else {
  1771. X        /* error listing dir */
  1772. X        if (c->pathname) free(c->pathname);
  1773. X        uip_retr_done(c, status);
  1774. X    }
  1775. X}
  1776. X
  1777. Xstatic int
  1778. Xuip_retr_2(reqp, pathname)
  1779. Xwf_req *reqp;
  1780. Xchar *pathname;
  1781. X{
  1782. X    int ret;
  1783. X    wf_ih ih;
  1784. X    wf_thrd *c;
  1785. X
  1786. X    c = thrd_alloc();
  1787. X    c->req = *reqp;
  1788. X    c->fhp = ALLOC(wf_fh);
  1789. X
  1790. X    if (pathname[0] == '+') {
  1791. X        ret = root_fhn2ih(pathname, &ih);
  1792. X    } else {
  1793. X        ret = root_name2ih(pathname, &ih);
  1794. X    }
  1795. X    if (ret == WF_REP_OK || ret == WF_REP_WAIT) {
  1796. X        c->parent_volp = ih.parent_volp;
  1797. X        c->child_volp = ih.child_volp;
  1798. X        ih2fh(&ih, c->fhp);
  1799. X        if (ret == WF_REP_OK) {
  1800. X            c->reply = uip_retr_done;
  1801. X        } else {
  1802. X            c->pathname = pathname;
  1803. X            c->reply = uip_retr_loop;
  1804. X        }
  1805. X        if (ih.filep->fattr.type == NFDIR)
  1806. X            proto_readdir(c);
  1807. X        else
  1808. X            proto_read(c);
  1809. X    }
  1810. X    else {
  1811. X        uip_retr_done(c, ret);
  1812. X    }
  1813. X    return ret;
  1814. X}
  1815. X
  1816. Xstatic void
  1817. Xuip_retr(reqp, arg)
  1818. Xwf_req *reqp;
  1819. Xchar *arg;
  1820. X{
  1821. X    req_send(reqp, "220 %03d fil %s\n", reqp->id, arg);
  1822. X    uip_retr_2(reqp, strdup(arg));
  1823. X}
  1824. X
  1825. Xstatic void
  1826. Xuip_load(reqp, arg)
  1827. Xwf_req *reqp;
  1828. Xchar *arg;
  1829. X{
  1830. X    int ret;
  1831. X    wf_ih ih;
  1832. X
  1833. X    ret = root_name2ih(arg, &ih);
  1834. X    if (ret == WF_REP_OK) {
  1835. X        req_send(reqp, "220-%03d vol %s\n", reqp->id, arg);
  1836. X        req_send(reqp, "211.%03d Volume \"%s\" is now visible.\n",
  1837. X             reqp->id, arg);
  1838. X    }
  1839. X    else {
  1840. X        req_send(reqp, "520-%03d vol %s\n", reqp->id, arg);
  1841. X        req_send(reqp, "511.%03d \"%s\": No such volume.\n",
  1842. X             reqp->id, arg);
  1843. X    }
  1844. X}
  1845. X
  1846. Xstatic void
  1847. Xuip_unload(reqp, arg)
  1848. Xwf_req *reqp;
  1849. Xchar *arg;
  1850. X{
  1851. X    int ret;
  1852. X
  1853. X    ret = root_deletevol(arg);
  1854. X    if (ret == WF_REP_OK) {
  1855. X        req_send(reqp, "220-%03d vol %s\n", reqp->id, arg);
  1856. X        req_send(reqp, "211.%03d Volume \"%s\" is now invisible.\n",
  1857. X             reqp->id, arg);
  1858. X    } else {
  1859. X        req_send(reqp, "520-%03d vol %s\n", reqp->id, arg);
  1860. X        req_send(reqp, "511.%03d \"%s\": No such volume.\n",
  1861. X             reqp->id, arg);
  1862. X    }
  1863. X}
  1864. X
  1865. Xstatic void
  1866. Xuip_close(reqp)
  1867. Xwf_req *reqp;
  1868. X{
  1869. X    int optlen, sotype;
  1870. X
  1871. X    if (reqp->flag & WF_REQ_PRIV) {
  1872. X        dlog("privileged connection closed");
  1873. X    }
  1874. X    optlen = sizeof(int);
  1875. X    getsockopt(reqp->so, SOL_SOCKET, SO_TYPE, &sotype, &optlen);
  1876. X    if (sotype == SOCK_STREAM) {
  1877. X        so_clear(reqp->so);
  1878. X        so_unregister(reqp->so, WF_SO_ALL);
  1879. X        close(reqp->so);
  1880. X        uip_free(reqp);
  1881. X    }
  1882. X    if (cs_ftp_debug == reqp) {    /* XXX */
  1883. X        cs_ftp_debug = (wf_req *) 0;
  1884. X    }
  1885. X}
  1886. X
  1887. Xstatic
  1888. Xvoid
  1889. Xuip_parse(reqp, buf)
  1890. Xwf_req *reqp;
  1891. Xchar *buf;
  1892. X{
  1893. X    int ret;
  1894. X    char *arg;
  1895. X
  1896. X    if (! isalpha(buf[0])) {
  1897. X        req_send(reqp, "510.000 Illegal command.\n");
  1898. X        return;
  1899. X    }
  1900. X    reqp->id = uip_id();
  1901. X    arg = buf+5;
  1902. X    switch (buf[0]) {
  1903. X    case 'D':
  1904. X        if (strncmp(buf, "DMSG", 4) == 0) {
  1905. X            uip_dmsg(reqp, arg);
  1906. X        }
  1907. X        else if (strncmp(buf, "DIAG", 4) == 0) {
  1908. X            uip_diag(reqp, arg);
  1909. X        }
  1910. X        break;
  1911. X    case 'E':
  1912. X        if (strncmp(buf, "EMSG", 4) == 0) {
  1913. X            uip_emsg(reqp, arg);
  1914. X        }
  1915. X        break;
  1916. X    case 'F':
  1917. X        if (strncmp(buf, "FILL", 4) == 0) {
  1918. X        }
  1919. X        break;
  1920. X    case 'J':
  1921. X        if (strncmp(buf, "JUNK", 4) == 0) {
  1922. X        }
  1923. X        break;
  1924. X    case 'R':
  1925. X        if (strncmp(buf, "RTOC", 4) == 0) {
  1926. X            uip_rtoc(reqp, arg);
  1927. X        }
  1928. X        else if (strncmp(buf, "RETR", 4) == 0) {
  1929. X            uip_retr(reqp, arg);
  1930. X        }
  1931. X        break;
  1932. X    case 'L':
  1933. X        if (strncmp(buf, "LOAD", 4) == 0) {
  1934. X            uip_load(reqp, arg);
  1935. X        }
  1936. X        break;
  1937. X    case 'U':
  1938. X        if (strncmp(buf, "UNLD", 4) == 0) {
  1939. X            uip_unload(reqp, arg);
  1940. X        }
  1941. X        break;
  1942. X    case 'Q':
  1943. X        if (strncmp(buf, "QUIT", 4) == 0) {
  1944. X            uip_close(reqp);
  1945. X            break;
  1946. X        }
  1947. X    default:
  1948. X        req_send(reqp, "513.%03d Unknown command.\n", reqp->id);
  1949. X        break;
  1950. X    }
  1951. X}
  1952. X
  1953. X/* WWUIP over TCP and "connected UDP" */
  1954. Xstatic void
  1955. Xuip_recv(reqp)
  1956. Xwf_req *reqp;
  1957. X{
  1958. X    char *buf, *nl;
  1959. X    long navail;
  1960. X    int nread, ret, optlen, sinlen;
  1961. X    int so = reqp->so;
  1962. X
  1963. X    /*
  1964. X     * check data
  1965. X     */
  1966. X    ioctl(so, FIONREAD, &navail);
  1967. X    nread = MIN(navail, NFS_MAXDATA);
  1968. X    /*
  1969. X     * Beware: FIONREAD gives incorrect value for UDP sockets.
  1970. X     * We cannot trust "nread", but at least it's larger than
  1971. X     * actually available bytes. 'mbuf' structure is assumed here,
  1972. X     * but even if it doesn't hold, correct UDP implementation
  1973. X     * should provide correct "nread" values.
  1974. X     */
  1975. X    if (nread == 0) {
  1976. X        optlen = sizeof(int);
  1977. X        getsockopt(so, SOL_SOCKET, SO_ERROR, &ret, &optlen);
  1978. X        if (ret)
  1979. X            dlog("uip_recv: %s", sys_errlist[ret]);
  1980. X        uip_close(reqp);
  1981. X        return;
  1982. X    }
  1983. X
  1984. X    /*
  1985. X     * get one line
  1986. X     */
  1987. X    buf = so_getbuf(so);
  1988. X    sinlen = sizeof(reqp->sin);
  1989. X    ret = recvfrom(so, buf, nread, MSG_PEEK,
  1990. X               (struct sockaddr *) &reqp->sin, &sinlen);
  1991. X    /*
  1992. X     * recvfrom() gives number of bytes read, and it's *correct*.
  1993. X     */
  1994. X    buf[ret] = '\0';
  1995. X    if ((nl = strchr(buf, '\n')) == NULL) return;
  1996. X    nread = nl - buf + 1;
  1997. X    nread = recvfrom(so, buf, nread, 0,
  1998. X             (struct sockaddr *) &reqp->sin, &sinlen);
  1999. X    if (nread == 1)
  2000. X        return;        /* newline alone doesn't make sense */
  2001. X    if (buf[nread-2] == '\r') {
  2002. X        /* telnet oddity here */
  2003. X        buf[nread-2] = '\0';
  2004. X    } else {
  2005. X        buf[nread-1] = '\0';
  2006. X    }
  2007. X#ifdef DEBUG_UIP
  2008. X    dlog("%s.%d -> %s", inet_ntoa(reqp->sin.sin_addr),
  2009. X         ntohs(reqp->sin.sin_port), buf);
  2010. X#endif
  2011. X    if (inet_netof(reqp->sin.sin_addr) == inet_netof(cs_ipaddr)
  2012. X        || reqp->sin.sin_addr.s_addr == inet_addr("127.0.0.1")) {
  2013. X        /*
  2014. X         * Accept request only from the same network.
  2015. X         * Further access control can be provided in each volume.
  2016. X         */
  2017. X        uip_parse(reqp, buf);
  2018. X    } else {
  2019. X        req_send(reqp, "510.000 Access denied.\n");
  2020. X        dlog("Invalid access from %s", inet_ntoa(reqp->sin.sin_addr));
  2021. X    }
  2022. X}
  2023. X
  2024. Xstatic void
  2025. Xuip_recvfrom(so)
  2026. Xint so;
  2027. X{
  2028. X    static wf_req req;    /* XXX bug if two UIP/UDP come simutaneously */
  2029. X
  2030. X    bzero(&req, sizeof(req));
  2031. X    req.so = so;
  2032. X    uip_recv(&req);
  2033. X}
  2034. X
  2035. X/* start WWUIP over TCP */
  2036. Xstatic void
  2037. Xuip_accept(so)
  2038. Xint so;
  2039. X{
  2040. X    int sinlen;
  2041. X    wf_req *p = uip_alloc();
  2042. X
  2043. X    /*
  2044. X     * accept
  2045. X     */
  2046. X    sinlen = sizeof(sockaddr_in);
  2047. X    p->so = accept(so, (struct sockaddr *) &p->sin, &sinlen);
  2048. X    if (p->so < 0) {
  2049. X        errno_diag();
  2050. X        return;
  2051. X    }
  2052. X
  2053. X    /*
  2054. X     * check peer privilege
  2055. X     */
  2056. X    if (bcmp(&p->sin.sin_addr, &cs_ipaddr, sizeof (struct in_addr)) == 0) {
  2057. X        if (ntohs(p->sin.sin_port) < IPPORT_RESERVED) {
  2058. X            p->flag |= WF_REQ_PRIV;
  2059. X            dlog("privileged connection established");
  2060. X        }
  2061. X    } else {
  2062. X#if 0
  2063. X        /* TCP connection from other hosts.
  2064. X         * Reject it to conserve open file descriptor.
  2065. X         */
  2066. X        close(p->so);
  2067. X        return;
  2068. X#endif
  2069. X    }
  2070. X    so_register(p->so, WF_SO_READ);
  2071. X    so_callback(p->so, uip_recv, p);
  2072. X}
  2073. X
  2074. X/*
  2075. X * WWUIP/TCP for telnet,
  2076. X * WWUIP/UDP for Tcl/Tk and other utilities.
  2077. X *
  2078. X * UDP version is preferable since it doesn't consume file descriptor..
  2079. X */
  2080. Xvoid
  2081. Xuip_start()
  2082. X{
  2083. X    int opt, tcp_so, udp_so;
  2084. X    struct sockaddr_in sin;
  2085. X    int ret;
  2086. X
  2087. X    /*
  2088. X     * create tcp socket
  2089. X     */
  2090. X    tcp_so = socket(AF_INET, SOCK_STREAM, 0);
  2091. X    if (tcp_so < 0) {
  2092. X        errno_diag();
  2093. X        return;
  2094. X    }
  2095. X    opt = 1;
  2096. X#if 0    /* for debug_malloc ? */
  2097. X    ioctl(tcp_so, FIONBIO, &opt);
  2098. X#endif
  2099. X    setsockopt(tcp_so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
  2100. X    so_register(tcp_so, WF_SO_READ);
  2101. X    bzero(&sin, sizeof(sin));
  2102. X    sin.sin_family = AF_INET;
  2103. X    sin.sin_addr.s_addr = htonl(INADDR_ANY);
  2104. X    sin.sin_port = htons(8002);
  2105. X    ret = bind(tcp_so, (struct sockaddr *) &sin, sizeof (sin));
  2106. X    if (ret < 0) {
  2107. X        errno_diag();
  2108. X        return;
  2109. X    }
  2110. X    listen(tcp_so, 1);
  2111. X    so_callback(tcp_so, uip_accept, tcp_so);
  2112. X
  2113. X    /*
  2114. X     * create udp socket
  2115. X     */
  2116. X    udp_so = socket(AF_INET, SOCK_DGRAM, 0);
  2117. X    if (udp_so < 0) {
  2118. X        errno_diag();
  2119. X        return;
  2120. X    }
  2121. X    opt = 1;
  2122. X    ioctl(udp_so, FIONBIO, &opt);
  2123. X    so_register(udp_so, WF_SO_READ);
  2124. X    bzero(&sin, sizeof(sin));
  2125. X    sin.sin_family = AF_INET;
  2126. X    sin.sin_addr.s_addr = htonl(INADDR_ANY);
  2127. X    sin.sin_port = htons(8002);
  2128. X    ret = bind(udp_so, (struct sockaddr *) &sin, sizeof (sin));
  2129. X    if (ret < 0) {
  2130. X        errno_diag();
  2131. X        return;
  2132. X    }
  2133. X    so_callback(udp_so, uip_recvfrom, udp_so);
  2134. X}
  2135. X
  2136. END_OF_FILE
  2137.   if test 12592 -ne `wc -c <'csd/uip.c'`; then
  2138.     echo shar: \"'csd/uip.c'\" unpacked with wrong size!
  2139.   fi
  2140.   # end of 'csd/uip.c'
  2141. fi
  2142. if test -f 'gtr/resolv.pl' -a "${1}" != "-c" ; then 
  2143.   echo shar: Will not clobber existing file \"'gtr/resolv.pl'\"
  2144. else
  2145.   echo shar: Extracting \"'gtr/resolv.pl'\" \(11569 characters\)
  2146.   sed "s/^X//" >'gtr/resolv.pl' <<'END_OF_FILE'
  2147. X#!/usr/local/bin/perl
  2148. X
  2149. X# DNS resolver library.  See RFC1035 for more details.
  2150. X# by Marc Horowitz <marc@mit.edu>
  2151. X
  2152. X# $Id: resolv.pl,v 1.3 91/11/09 00:35:49 marc Exp $
  2153. X
  2154. X# The interface works like this (all functions are in the main package)
  2155. X#
  2156. X# res_init()
  2157. X#    One-time initialization
  2158. X#
  2159. X# res_open($nameserver)
  2160. X#    Sets up a connection to $nameserver.
  2161. X#    If $nameserver is undefined or empty, then the server is
  2162. X#    looked up in /etc/resolv.conf.  Returns the filehandle.
  2163. X#
  2164. X# res_mkquery($name, $type, $class, $id)
  2165. X#    builds and returns a query for the given name, type, class,
  2166. X#    and id.  If no id is given, a random ID is chosen.
  2167. X#
  2168. X# res_send($fh, $query)
  2169. X#    sends $query to the server at $fh.  Returns the response from the
  2170. X#    server.
  2171. X#
  2172. X# response format:
  2173. X# [0] = id
  2174. X# [1] = authoritative
  2175. X# [2] = recursion available
  2176. X# [3] = query name
  2177. X# [4] = query class
  2178. X# [5] = query type
  2179. X# [6] = start of answers
  2180. X# [7] = end of answers
  2181. X# [8] = start of authority records
  2182. X# [9] = end of authority records
  2183. X# [10] = start of add'l records
  2184. X# [11] = end of add'l records
  2185. X# [12] ...   resource records (in multiples of 5)
  2186. X#
  2187. X# The variable res'options can be set to any of the values
  2188. X# which _res.options can be set to.  The constants will be in the 
  2189. X# main package.
  2190. X#
  2191. X# Not implemented yet:
  2192. X# Only one query is sent out.  That is, RES_DNSRCH is ignored, and
  2193. X#    only the primary nameserver is used.
  2194. X# RES_DEBUG doesn't print anything
  2195. X#    
  2196. X
  2197. X## Everything after this is code.  If you look at it, you're
  2198. X## violating an abstraction barrier.  Shame on you.  :-)
  2199. X
  2200. X# hack! hack!  This is to confuse the byte order stuff in arpa/nameser.h
  2201. X# nothing here depends on it anyway.
  2202. X
  2203. Xsub MIPSEB {1;}
  2204. X
  2205. Xrequire 'sys/socket.ph' || die "can\'t do sys/socket.ph: $@";
  2206. Xrequire 'arpa/nameser.ph' || die "can\'t do arpa/nameser.ph: $@";
  2207. Xrequire 'resolv.ph' || die "can\'t do resolv.ph: $@";
  2208. X
  2209. X# who? me? kludge?
  2210. X
  2211. Xundef &MIPSEB;
  2212. X
  2213. Xpackage res;
  2214. X
  2215. X# Create conversion arrays unfortunately, I need to hardcode lists
  2216. X# of the types and classes.
  2217. X
  2218. X@qtypes = ("A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", "NULL",
  2219. X        "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", "UINFO", "UID", "GID",
  2220. X        "UNSPEC", "UNSPECA", "AXFR", "MAILB", "MAILA", "ANY");
  2221. X
  2222. X@qclasses = ("IN", "CHAOS", "HS", "ANY");
  2223. X
  2224. Xfor (@qtypes) {
  2225. X    eval "\@qtype[&main'T_$_] = \"$_\";\$qtype{\$_} = &main'T_$_;";
  2226. X}
  2227. X
  2228. Xfor (@qclasses) {
  2229. X    eval "\@qclass[&main'C_$_] = \"$_\";\$qclass{\$_} = &main'C_$_;";
  2230. X}
  2231. X
  2232. Xsub qtype_strtonum {
  2233. X    return($qtype{$_[0]} || -1);
  2234. X}
  2235. X
  2236. Xsub qclass_strtonum {
  2237. X    return($qclass{$_[0]} || -1);
  2238. X}
  2239. X
  2240. Xsub qtype_numtostr {
  2241. X    local($str) = @qtype[$_[0]];
  2242. X
  2243. X    if (defined($str)) {
  2244. X        return($str);
  2245. X    } else {
  2246. X        return("$_[0]");
  2247. X    }
  2248. X}
  2249. X
  2250. Xsub qclass_numtostr {
  2251. X    local($str) = @qclass[$_[0]];
  2252. X
  2253. X    if (defined($str)) {
  2254. X        return($str);
  2255. X    } else {
  2256. X        return("$_[0]");
  2257. X    }
  2258. X}
  2259. X
  2260. X# option bits and defaults
  2261. X
  2262. X$options = &main'RES_DEFAULT;
  2263. X$domain = "";
  2264. X
  2265. Xsub debug { $options & &main'RES_DEBUG; }
  2266. X
  2267. Xsub ipaddr {
  2268. X    if ($_[0] =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
  2269. X    $saddr = pack("CCCC", $1, $2, $3, $4);
  2270. X    } else {
  2271. X    ($saddr = ((gethostbyname($_[0]))[4] || undef)) ||
  2272. X        return(undef);
  2273. X    }
  2274. X}
  2275. X
  2276. Xsub read_conf {
  2277. X    return if ($domain);
  2278. X
  2279. X    local($addr);
  2280. X
  2281. X    print "Reading /etc/resolv.conf\n" if &debug;
  2282. X
  2283. X    if (open(CONF,"/etc/resolv.conf")) {
  2284. X    local($") = ",";
  2285. X    while(<CONF>) {
  2286. X        chop;
  2287. X        if (/^domain\s+/) { $domain = $'; }
  2288. X        elsif (/^nameserver\s+/) {
  2289. X        if ($addr = &ipaddr($')) { push(@servers,$addr); }
  2290. X        }
  2291. X    }
  2292. X    close(CONF);
  2293. X    } else {
  2294. X    $domain = '';
  2295. X    @servers = ("\0\0\0\0");
  2296. X    }
  2297. X    print "domain is ",$domain,"\nresolvers are @servers\n" if &debug;
  2298. X}
  2299. X
  2300. X# one-time initialization
  2301. X
  2302. X$inited = 0;
  2303. X
  2304. Xsub main'res_init {
  2305. X    return if ($options & &main'RES_INIT);
  2306. X
  2307. X    local($fh);
  2308. X
  2309. X    socket(NSUDP, &main'AF_INET, &main'SOCK_DGRAM, &main'PF_UNSPEC) ||
  2310. X    die "socket: $!";
  2311. X
  2312. X    $options |= &main'RES_INIT;
  2313. X    &read_conf;
  2314. X
  2315. X    $fh = select(NSUDP); $| = 1;   # set nonbufferred
  2316. X    select($fh);
  2317. X}
  2318. X
  2319. X# begin a conversation with a nameserver
  2320. X
  2321. Xsub main'res_open {            # @_ = ($nameserver)
  2322. X    local($saddr,$port);
  2323. X
  2324. X    &main'res_init if (!($options & &main'RES_INIT));
  2325. X
  2326. X    if ($_[0]) {
  2327. X    if ($_[0] =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
  2328. X        $saddr = pack("CCCC", $1, $2, $3, $4);
  2329. X    } else {
  2330. X        ($saddr = ((gethostbyname($_[0]))[4] || undef)) ||
  2331. X        return(undef);
  2332. X    }
  2333. X    } else {
  2334. X    $saddr = $servers[0];
  2335. X    }
  2336. X
  2337. X    # lossage in /etc/services.  hardcode for now.
  2338. X    #$port = (getservbyname("nameserver","tcp"))[2];
  2339. X    $port = 53;
  2340. X
  2341. X    $port = pack("S n a4 x8",&main'AF_INET,$port,$saddr);
  2342. X
  2343. X    return($port);
  2344. X}
  2345. X
  2346. Xsub main'res_mkquery { # @_ = ($name,$type,$class,$id)
  2347. X    local($question);
  2348. X
  2349. X    print "building query for <$_[0],$_[1],$_[2]>\n" if &debug;
  2350. X
  2351. X    $question = (($options & &main'RES_RECURSE)? #  header
  2352. X         pack("n6",$_[3],0x0100,1,0,0,0):
  2353. X         pack("n6",$_[3],0x0000,1,0,0,0));
  2354. X    $question .= ((($options & &main'RES_DEFNAMES) &&
  2355. X           (substr($_[0],-1,1) ne "."))?
  2356. X          &unparse_name($_[0].".".$domain):
  2357. X          &unparse_name($_[0]));
  2358. X    $question .= pack("n n",&qtype_strtonum($_[1]), # query
  2359. X              &qclass_strtonum($_[2]));
  2360. X}
  2361. X
  2362. Xsub unparse_name {
  2363. X    local($label,$labellen,$str);
  2364. X    $str = "";
  2365. X    foreach $label (split(/\./,$_[0])) {
  2366. X        $labellen = length($label);
  2367. X        $str .= pack("Ca$labellen",$labellen,$label);
  2368. X    }
  2369. X    $str .= pack("C",0);        # root octet
  2370. X}
  2371. X
  2372. X%nstcp = ();            # assoc array of open VC's
  2373. X$sockcnt = "nstcp000";
  2374. X
  2375. Xsub main'res_send { # @_ = ($socket,$query)
  2376. X    local($sin,$len,$packet) = ($_[0],pack("n",length($_[1])),$_[1]);
  2377. X    local($fh,$resp);
  2378. X
  2379. X    if ($options & &main'RES_USEVC) { # 
  2380. X    $fh = $nstcp{$sin};
  2381. X    if (!$fh) {
  2382. X        $fh = $sockcnt++;
  2383. X
  2384. X        if (&debug) {
  2385. X        local($,) = (".");
  2386. X        print "Connecting to ",(unpack("S n C4",$sin))[2..5,1],"\n";
  2387. X        }
  2388. X
  2389. X        socket($fh,&main'AF_INET,&main'SOCK_STREAM,&main'PF_UNSPEC) ||
  2390. X        die "socket: $!";
  2391. X        connect($fh, $sin) || die "connect: $!";
  2392. X
  2393. X        $nstcp{$sin} = $fh;
  2394. X    }
  2395. X
  2396. X    if (&debug) {
  2397. X        local($,) = (".");
  2398. X        print "Sending to ",(unpack("S n C4",$sin))[2..5,1]," via TCP\n";
  2399. X    }
  2400. X
  2401. X    send($fh,$len,0);
  2402. X    send($fh,$packet,0);
  2403. X
  2404. X    if (&debug) {
  2405. X        local($,) = (".");
  2406. X        print "Receiving from ",(unpack("S n C4",$sin))[2..5,1]
  2407. X        ," via TCP\n";
  2408. X    }
  2409. X
  2410. X    read($fh,$len,2) || die "recv: $!,$@";
  2411. X    if ($len = unpack("n",$len)) {
  2412. X        read($fh,$resp,$len) || die "recv: $!";
  2413. X    }
  2414. X
  2415. X    print "Got a response (size=$len)\n" if (&debug);
  2416. X
  2417. X    if (! ($options & &main'RES_STAYOPEN)) {
  2418. X        foreach (keys(%nstcp)) {
  2419. X        if (&debug) {
  2420. X            local($,) = (".");
  2421. X            print "Disconnecting from ",(unpack("S n C4",$_))[2..5,1]
  2422. X            ,"\n";
  2423. X        }
  2424. X
  2425. X        close($_);
  2426. X        }
  2427. X        %nstcp = ();
  2428. X    }
  2429. X    } else {
  2430. X    if (&debug) {
  2431. X        local($,) = (".");
  2432. X        print "Sending to ",(unpack("S n C4",$sin))[2..5,1]," via UDP\n";
  2433. X    }
  2434. X
  2435. X    send(NSUDP,$packet,0,$sin) || die "send: $!";
  2436. X
  2437. X    if (&debug) {
  2438. X        local($,) = (".");
  2439. X        print "Receiving from ",(unpack("S n C4",$sin))[2..5,1]," via UDP\n";
  2440. X    }
  2441. X
  2442. X    $len = 512;
  2443. X    read(NSUDP,$resp,512,0) || die "recv: $!";
  2444. X
  2445. X    print "Got a response (size=$len)\n" if (&debug);
  2446. X    }
  2447. X
  2448. X    &parse_response($resp);
  2449. X}
  2450. X
  2451. Xsub parse_response { # @_ = ($response)
  2452. X    local($response,@resp,@ptr) = @_;
  2453. X
  2454. X    @ptr = ($response,0);
  2455. X
  2456. X    $header = &next_chars(12,@ptr);
  2457. X    ($id,$bits,$qdcount,$ancount,$nscount,$adcount) = unpack("n6",$header);
  2458. X    $auth = ($bits >> 10) & 0x01;
  2459. X    $recurse = ($bits >> 8) & 0x01;
  2460. X    if ((!$auth) && ($options & &main'RES_AAONLY)) {
  2461. X        ($ancount,$nscount,$adcount) = (0,0,0);
  2462. X    }
  2463. X        
  2464. X    $rrs = $ancount+$nscount+$adcount;
  2465. X    @resp = ($id,$auth,$recurse);        #         [0..2]
  2466. X
  2467. X    push(@resp,&parse_name(@ptr));         # QNAME        [3]
  2468. X    push(@resp,&next_netshort(@ptr));    # QTYPE        [4]
  2469. X    push(@resp,&next_netshort(@ptr));    # QCLASS    [5]
  2470. X
  2471. X    push(@resp,12);                #         [6]
  2472. X    push(@resp,@resp[$#resp]+5*$ancount-1);    #        [7]
  2473. X
  2474. X    push(@resp,@resp[$#resp]+1);        #        [8]
  2475. X    push(@resp,@resp[$#resp]+5*$nscount-1);    #        [9]
  2476. X
  2477. X    push(@resp,@resp[$#resp]+1);        #        [10]
  2478. X    push(@resp,@resp[$#resp]+5*$adcount-1);    #        [11]
  2479. X
  2480. X    for ($i = 0 ; $i < $rrs ; $i++) {
  2481. X        push(@resp,&parse_rrbits(@ptr));
  2482. X    }
  2483. X    return(@resp);
  2484. X}
  2485. X
  2486. Xsub parse_name {
  2487. X    local($name,$ch,$ptr,@temp) = ("",substr($_[0],$_[1],1));
  2488. X    while (ord($ch = substr($_[0],$_[1],1)) != 0) {
  2489. X        # Message compression (RFC1035 4.1.4)
  2490. X        if (ord($ch) >= 0xc0) {
  2491. X            $ptr = &next_netshort(@_) & 0x3fff;
  2492. X            @temp=($_[0],$ptr);
  2493. X            $name .= "".&parse_name(@temp);
  2494. X            return($name);
  2495. X        }
  2496. X        $name .= &next_str(@_).".";
  2497. X    }
  2498. X    &next_chars(1,@_);    # move past \0
  2499. X    if ($name eq "") { $name = ".."; }
  2500. X    chop($name);  # remove trailing "."
  2501. X    return($name);
  2502. X}
  2503. X
  2504. Xsub parse_rrbits {
  2505. X    local(@rrec,$name,$rdlen,$pfct);
  2506. X    @rrec = ();
  2507. X
  2508. X    $name = &parse_name(@_);
  2509. X    # if NAME is an odd number of bytes, eat an extra byte
  2510. X    if (($name == "") || (length($name)%2 == 1)) {&next_chars(1,$_[0]);}
  2511. X    @rrec = ($name);                    # NAME
  2512. X    push(@rrec,&qtype_numtostr(&next_netshort(@_)));    # TYPE
  2513. X    push(@rrec,&qclass_numtostr(&next_netshort(@_)));    # CLASS
  2514. X    push(@rrec,&next_netlong(@_));                # TTL (integer)
  2515. X
  2516. X    $rdlen = &next_netshort(@_);
  2517. X#    push(@rrec,&next_chars($rdlen,@_));            # RDATA
  2518. X    $pfct = "rrparse_".&qtype_numtostr($rrec[1]);
  2519. X    push(@rrec,&$pfct(@_,$rdlen));                # RDATA
  2520. X    return(@rrec);
  2521. X}
  2522. X
  2523. Xsub next_netshort {unpack("n",&next_chars(2,@_));}
  2524. Xsub next_netlong  {unpack("N",&next_chars(4,@_));}
  2525. X
  2526. X# strips the first character-string from the argument, and returns it as a
  2527. X# perl string
  2528. Xsub next_str {
  2529. X    local($cslen);
  2530. X    $cslen = unpack("C",&next_chars(1,@_));
  2531. X    &next_chars($cslen,@_);
  2532. X}
  2533. X
  2534. X# returns the first $_[0] chars at position $_[2] in string $_[1]
  2535. X# and increments $_[2]
  2536. Xsub next_chars {
  2537. X    local($len,$str) = (length($_[1]),$_[1]);
  2538. X    $_[2] += $_[0];
  2539. X    substr($_[1],$_[2]-$_[0],$_[0]);
  2540. X}
  2541. X
  2542. X# routines to parse apart the rrdata
  2543. X
  2544. Xsub rrparse_A {
  2545. X    join('.',unpack("C4",&next_chars(4,@_)));
  2546. X}
  2547. X
  2548. Xsub rrparse_NS {
  2549. X    join('.',&parse_name(@_));
  2550. X}
  2551. X
  2552. Xsub rrparse_MD {
  2553. X    join('.',&parse_name(@_));
  2554. X}
  2555. X
  2556. Xsub rrparse_MF {
  2557. X    join('.',&parse_name(@_));
  2558. X}
  2559. X
  2560. Xsub rrparse_CNAME {
  2561. X    join('.',&parse_name(@_));
  2562. X}
  2563. X
  2564. Xsub rrparse_SOA {
  2565. X    join(' ',
  2566. X     join('.',&parse_name(@_)),
  2567. X     join('.',&parse_name(@_)),
  2568. X     &next_netlong(@_),
  2569. X     &next_netlong(@_),
  2570. X     &next_netlong(@_),
  2571. X     &next_netlong(@_),
  2572. X     &next_netlong(@_));
  2573. X}
  2574. X
  2575. Xsub rrparse_MB {
  2576. X    join('.',&parse_name(@_));
  2577. X}
  2578. X
  2579. Xsub rrparse_MG {
  2580. X    join('.',&parse_name(@_));
  2581. X}
  2582. X
  2583. Xsub rrparse_MR {
  2584. X    join('.',&parse_name(@_));
  2585. X}
  2586. X
  2587. Xsub rrparse_NULL {
  2588. X    return(&next_chars($_[2],@_));
  2589. X}
  2590. X
  2591. Xsub rrparse_WKS {
  2592. X    local(@resp,$bitmap,$len,%bit);
  2593. X
  2594. X    push(@resp,
  2595. X     &rrparse_A(@_),
  2596. X     ord(&next_chars(1,@_)));
  2597. X    $bitmap = &next_chars($_[2]-5,@_);
  2598. X    @bit{0..(length($bitmap)*8)} = split(//,unpack("B*", $bitmap));
  2599. X    push(@resp, grep($bit{$_},keys(%bit)));
  2600. X
  2601. X#    for (unpack("B$len", $bitmap)) {
  2602. X#    push(@resp, $_) if $_;
  2603. X#    }
  2604. X
  2605. X#    for ($i=0;$i<length($bitmap)*8;$i++) {
  2606. X#    if (vec($bitmap,$i,1)) { push(@resp,$i); }
  2607. X#    }
  2608. X    join(' ',@resp);
  2609. X}
  2610. X
  2611. Xsub rrparse_PTR {
  2612. X    join('.',&parse_name(@_));
  2613. X}
  2614. X
  2615. Xsub rrparse_HINFO {
  2616. X    &next_str(@_).$;.&next_str(@_);
  2617. X}
  2618. X
  2619. Xsub rrparse_MINFO {
  2620. X    join('.',&parse_name(@_)).",".join('.',&parse_name(@_));
  2621. X}
  2622. X
  2623. Xsub rrparse_MX {
  2624. X    &next_netshort(@_)." ".join('.',&parse_name(@_));
  2625. X}
  2626. X
  2627. Xsub rrparse_TXT {
  2628. X    local(@data,$end);
  2629. X    $end = $_[1]+$_[2];
  2630. X    while ($_[1] < $end) {
  2631. X    push(@data,&next_str(@ptr));
  2632. X    }
  2633. X    if ($_[1] > $end) { print STDERR "Something weird in rrparse_TXT\n"; }
  2634. X    join($;,@data);
  2635. X}
  2636. X
  2637. Xsub rrparse_UNSPEC {
  2638. X    &next_chars($_[2],@_);
  2639. X}
  2640. X
  2641. Xsub rrparse_UNSPECA {
  2642. X    &next_chars($_[2],@_);
  2643. X}
  2644. X
  2645. Xsub rrparse {
  2646. X    local($type,$class) = (&qtype_numtostr($_[1]),&qclass_numtostr($_[2]));
  2647. X    local(@rrout);
  2648. X
  2649. X    eval("\@rrout = &rrparse_$type(\$_[4])") || (@rrout = ("< ".$_[4]." >"));
  2650. X    return($_[0],$type,$class,$_[3],@rrout);
  2651. X}
  2652. X
  2653. Xsub qdparse {
  2654. X    return($_[0],&qtype_numtostr($_[1]),&qclass_numtostr($_[2]));
  2655. X}
  2656. END_OF_FILE
  2657.   if test 11569 -ne `wc -c <'gtr/resolv.pl'`; then
  2658.     echo shar: \"'gtr/resolv.pl'\" unpacked with wrong size!
  2659.   fi
  2660.   # end of 'gtr/resolv.pl'
  2661. fi
  2662. if test -f 'mosaic/htget.pl' -a "${1}" != "-c" ; then 
  2663.   echo shar: Will not clobber existing file \"'mosaic/htget.pl'\"
  2664. else
  2665.   echo shar: Extracting \"'mosaic/htget.pl'\" \(12127 characters\)
  2666.   sed "s/^X//" >'mosaic/htget.pl' <<'END_OF_FILE'
  2667. X#!/usr/local/bin/perl
  2668. X#
  2669. X# htget               --- recursively get HTMLs starting at a given URL
  2670. X#
  2671. X# Given a starting URL, htget will recursively retrieve HTML pages.
  2672. X# It will also generate "htget.log" -- a table of titles and hosts.
  2673. X# Tries to find as many new hosts as possible, and strictly
  2674. X# limits the number of pages it will request from any one server.
  2675. X#
  2676. X# htget will stop when $maxtotal pages are retrieved (1000!),
  2677. X# or when the all pages were retrieved,
  2678. X# or when SIGINT is received (^C).
  2679. X#
  2680. X# NB: to get all pages recursively, try:
  2681. X#       htget -ls <home-page>
  2682. X#
  2683. X# Author: Youki Kadobayashi <youki@wide.ad.jp>
  2684. X# derived from "explore" written by: Oscar Nierstrasz oscar@cui.unige.ch
  2685. X# This file is part of WWFS.
  2686. X#
  2687. X#v = '(v1.0)'; # August 30, 1993
  2688. X#v = '(v1.1)'; # August 31 -- added triggering of xmosaic
  2689. X#v = '(v1.2)'; # Sept 1 -- added various options; SIGINT handling
  2690. X#v = '(v1.3)'; # Oct 21 -- fixed counting of hosts; added -d
  2691. X#v = '(v1.4)'; # Oct 23 -- fixed sigint to allow <CR> to continue
  2692. X#                #       -- fixed printing of $hostsig
  2693. X#v = '(v1.0)'; # Nov 14, 1993 -- htget initial revision
  2694. X$v = '(v1.1)'; # Dec 8, 1993 -- htget initial revision
  2695. X
  2696. Xrequire '/etc/csd.pl';
  2697. Xunshift(@INC, "$WWFSDIR/lib");
  2698. Xrequire 'url.pl';
  2699. Xrequire 'dirutil.pl';
  2700. X
  2701. X$usg = 'Usage: htget [<options>] <http-url> <output file>
  2702. X    <http-url>    -- URL to start with (no default)
  2703. X    <output file>    -- default is htget.log
  2704. X    -m <maxpages>    -- max pages to get per site (default 5)
  2705. X    -t <maxtotal>    -- max total pages to get (default 100)
  2706. X    -h <maxhosts>    -- max hosts to explore (default unlimited)
  2707. X    -s <savedir>    -- directory to save pages to (default current)
  2708. X    -a <altdir>    -- alternate directory to search
  2709. X    -x <regexp>    -- exclude files matching regexp
  2710. X    -ls        -- list all pages at starting site (use with care!)
  2711. X    -i        -- also get embedded images
  2712. X';
  2713. X$maxpages = 5;          # max pages to retrieve per site
  2714. X$maxtotal = 100;        # max pages to retrieve in total
  2715. X$maxhosts = undef;      # max hosts to visit
  2716. X
  2717. X$hosts = 1;             # hosts visited (always at least 1)
  2718. X
  2719. Xchop($date = `date +%d.%m.%y`);
  2720. X$sig = "This page was generated by htget $v on $date.\n";
  2721. X
  2722. X# A good default starting point:
  2723. X# $whatsnew = "http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/whats-new.html";
  2724. X# $start = "http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/StartingPoints/NetworkStartingPoints.html";
  2725. X
  2726. X# default log file:
  2727. X$deflog = "htget.log";
  2728. X
  2729. X# default save directory:
  2730. X$savedir = ".";
  2731. X
  2732. Xwhile ($#ARGV >= $[) {
  2733. X    $arg = shift @ARGV;
  2734. X
  2735. X    if ($arg eq "-m") {
  2736. X        $arg = shift @ARGV;
  2737. X        if ($arg =~ /^\d+$/){
  2738. X            print STDERR "maxpages = $arg (was $maxpages)\n";
  2739. X            $maxpages = $arg;
  2740. X            next;
  2741. X        }
  2742. X        else { die "Bad arg for -m\n$usg"; }
  2743. X    }
  2744. X
  2745. X    if ($arg eq "-t") {
  2746. X        $arg = shift @ARGV;
  2747. X        if ($arg =~ /^\d+$/){
  2748. X            print STDERR "maxtotal = $arg (was $maxtotal)\n";
  2749. X            $maxtotal = $arg;
  2750. X            next;
  2751. X        }
  2752. X        else { die "Bad arg for -t\n$usg"; }
  2753. X    }
  2754. X
  2755. X    if ($arg eq "-h") {
  2756. X        $arg = shift @ARGV;
  2757. X        if ($arg =~ /^\d+$/){
  2758. X            print STDERR "maxhosts = $arg (was $maxhosts)\n";
  2759. X            $maxhosts = $arg;
  2760. X            next;
  2761. X        }
  2762. X        else { die "Bad arg for -h\n$usg"; }
  2763. X    }
  2764. X
  2765. X    if ($arg eq "-s") {
  2766. X        $arg = shift @ARGV;
  2767. X        if (-d $arg) {
  2768. X            print STDERR "directory = $arg (was $savedir)\n";
  2769. X            $savedir = $arg;
  2770. X            next;
  2771. X        }
  2772. X        else { die "Bad arg for -s\n$usg"; }
  2773. X    }
  2774. X
  2775. X    if ($arg eq "-a") {
  2776. X        $arg = shift @ARGV;
  2777. X        if (-d $arg) {
  2778. X            print STDERR "directory = $arg (was $altdir)\n";
  2779. X            $altdir = $arg;
  2780. X            next;
  2781. X        }
  2782. X        else { die "Bad arg for -a\n$usg"; }
  2783. X    }
  2784. X
  2785. X    if ($arg eq "-x") {
  2786. X        $arg = shift @ARGV;
  2787. X        print STDERR "exclude = $arg\n";
  2788. X        $exclude = $arg;
  2789. X        next;
  2790. X    }
  2791. X
  2792. X    if ($arg eq "-ls") {
  2793. X        $maxhosts = 1;
  2794. X        $maxtotal = $maxpages = 1000;
  2795. X        next;
  2796. X    }
  2797. X
  2798. X    if ($arg eq "-i") { $img = 1; next; }
  2799. X    if ($arg eq "-h") { die "$usg"; }
  2800. X    if ($arg =~ /^-/) { die "Invalid flag\n$usg"; }
  2801. X    if ($arg =~ /^http:/) {
  2802. X        if ($start) { die "Please give only one URL\n$usg"; }
  2803. X        $start = $arg;
  2804. X    }
  2805. X    else {
  2806. X        if ($log) { die "Please give only one output file\n$usg"; }
  2807. X        $log = $arg;
  2808. X    }
  2809. X}
  2810. X
  2811. Xunless ($log) { $log = $deflog; }
  2812. X$dump = $log;
  2813. X$dump =~ s/\.[a-z]+/.dump/ || ($dump = "$log.dump");
  2814. Xunless ($start || -f $dump) { die "$usg"; }
  2815. X
  2816. X(open(STDOUT,">>$log")) || die "Can't create/append $log\n";
  2817. X$| = 1;
  2818. Xprint STDERR "Writing output to $log\n";
  2819. X
  2820. Xif (-f $dump && open (DUMP, $dump)) {
  2821. X    print STDERR "Reading TODOs from $dump...\n";
  2822. X    $page = <DUMP>;
  2823. X    @tocheck = split("\n", $page);
  2824. X    close (DUMP);
  2825. X    unlink($dump);
  2826. X    $start = shift @tocheck;
  2827. X}
  2828. X
  2829. X&explore($start);
  2830. X
  2831. X# Explore the web, starting at $url.
  2832. X# Maintains a list @tocheck of URLs to try.
  2833. Xsub explore {
  2834. X    local($url) = @_;
  2835. X    if ($maxhosts == 1) {
  2836. X        print "Log of HTML transfer from $url\n$sig\n";
  2837. X    }
  2838. X    else {
  2839. X        print "Log of HTML transfer starting at $url\n";
  2840. X        if ($maxhosts) {
  2841. X            print "Maximum hosts to visit = $maxhosts.\n";
  2842. X        }
  2843. X        print "Max pages per site = $maxpages.\n",
  2844. X            "Max total pages = $maxtotal.\n$sig\n";
  2845. X    }
  2846. X
  2847. X    $SIG{'INT'} = 'sigint'; # Stop when SIGINT is received
  2848. X    push(@tocheck,$url);    # Initialize
  2849. X    $seen{$url} = 1;        # Remember that we've seen it
  2850. X    ($thistype,$thishost, $thisport, $thispath, $request) =
  2851. X        &url'parse(undef,undef,undef,undef,$url);
  2852. X    $seenhost{$thishost} = 1;
  2853. X
  2854. X    while ($#tocheck >= $[) {
  2855. X        $url = shift @tocheck;
  2856. X        # Remember current host, port and path:
  2857. X        ($thistype,$thishost, $thisport, $thispath, $request) =
  2858. X            &url'parse(undef,undef,undef,undef,$url);
  2859. X        # Check file size:
  2860. X        $page = &url'http_head($thishost, $thisport, $request);
  2861. X        $title = split(/\n/, $page, 1);
  2862. X        if (($title =~ /Server Error:/)
  2863. X            || ($title =~ /Bad File Request/)
  2864. X            || ($title =~ /404 Not Found/)) {
  2865. X            print "Invalid page: $url\n";
  2866. X            next;
  2867. X        }
  2868. X        if ($page =~ /Content-length:\s+/) {
  2869. X            $length = $';
  2870. X        } else {
  2871. X            $length = 0;
  2872. X            print "No content-length: $url\n";
  2873. X        }
  2874. X        if (&gotit("$savedir/$request", "$altdir/$request")
  2875. X            && &length("$savedir/$request", "$altdir/$request") == $length) {
  2876. X            # Cached file seems to be valid
  2877. X            $page = &loadfile("$savedir/$request");
  2878. X        } else {
  2879. X            # Not fetched or invalid cache
  2880. X            print STDERR "Requesting $url\n";
  2881. X            unless ($page = &url'get($url)) {
  2882. X                print "Can't get $url\n";
  2883. X                next;
  2884. X            } ;
  2885. X
  2886. X            # Extract the title and detect errors
  2887. X            if ($page =~ m|<title>([^<]+)</title>|i)
  2888. X                { $title = $1; }
  2889. X            else { $title = "UNTITLED"; }
  2890. X            if (($title =~ /Server Error:/)
  2891. X                || ($title =~ /Bad File Request/)
  2892. X                || ($title =~ /404 Not Found/)) {
  2893. X                print "Invalid page: $url\n";
  2894. X                next;
  2895. X            }
  2896. X
  2897. X            &savefile($savedir . $request, $page);
  2898. X            &save_url($savedir . $request, $url);
  2899. X            if (!($maxhosts == 1)) { $hostsig = " ($thishost)"; }
  2900. X            $title =~ s/\n/ /g;
  2901. X            # This page is ok, so log it:
  2902. X            print "$title$hostsig\n";
  2903. X            # from the last request
  2904. X            if (++$entries >= $maxtotal) { &dump; last; }
  2905. X        }
  2906. X        foreach $href (&hrefs($page)) {
  2907. X            $href =~ s/#.*$//;
  2908. X            next if $href eq "";
  2909. X            # Parse the URL, if possible:
  2910. X            ($type,$host,$port,$path,$request) =
  2911. X                &url'parse($thistype,$thishost,
  2912. X                    $thisport,$thispath,$href);
  2913. X            unless ($type eq "http") { next; }
  2914. X            # Skip this host if invalid:
  2915. X            unless ($host) { next; }
  2916. X            # Convert from relative to absolute URL:
  2917. X            $href = "http://$host:$port$request";
  2918. X            # Skip if seen already:
  2919. X            if ($seen{$href}) { next; }
  2920. X            $seen{$href} = 1;
  2921. X            # Don't ask too many pages from a given host:
  2922. X            unless (++$count{$host} <= $maxpages) { next; }
  2923. X            # Only look at guaranteed .html files:
  2924. X            unless ($request =~ /\.html$/ || $request =~ /\/$/) {
  2925. X                if ($exclude && eval "\$request =~ $exclude") {
  2926. X                    next;
  2927. X                }
  2928. X            }
  2929. X            if ($seenhost{$host}) {
  2930. X                # Seen this host, so add to end of queue:
  2931. X                print STDERR "Pushing $href\n";
  2932. X                if ($request =~ /\.html$/
  2933. X                    || $request =~ /\/$/) {
  2934. X                    # HTML file -- add to checklist
  2935. X                    push(@tocheck,$href);
  2936. X                } else {
  2937. X                    # Plain file -- add to xfer list
  2938. X                    push (@toget, $href);
  2939. X                }
  2940. X            }
  2941. X            else {
  2942. X                if ($maxhosts) {
  2943. X                    if (++$hosts > $maxhosts) { next; }
  2944. X                }
  2945. X                # New host, so add to front:
  2946. X                print STDERR "Queueing $href\n";
  2947. X                if ($request =~ /\.html$/
  2948. X                    || $request =~ /\/$/) {
  2949. X                    # HTML file -- add to checklist
  2950. X                    unshift(@tocheck,$href);
  2951. X                } else {
  2952. X                    # Plain file -- add to xfer list
  2953. X                    unshift (@toget, $href);
  2954. X                }
  2955. X                $seenhost{$host} = 1;
  2956. X            }
  2957. X        }
  2958. X        if ($img) { push(@toget, &srcs($page)) };
  2959. X        foreach $url (@toget) {
  2960. X            # Parse the URL, if possible:
  2961. X            ($type,$host,$port,$path,$request) =
  2962. X                &url'parse($thistype,$thishost,
  2963. X                    $thisport,$thispath,$url);
  2964. X            unless ($type eq "http") { next; }
  2965. X            # Skip this host if invalid:
  2966. X            unless ($host) { next; }
  2967. X            # Convert from relative to absolute URL:
  2968. X            $url = "http://$host:$port$request";
  2969. X            # Check file size:
  2970. X            $page = &url'http_head($host, $port, $request);
  2971. X            $title = split(/\n/, $page, 1);
  2972. X            if (($title =~ /Server Error:/)
  2973. X                || ($title =~ /Bad File Request/)
  2974. X                || ($title =~ /404 Not Found/)) {
  2975. X                print "Invalid IMG: $url\n";
  2976. X                next;
  2977. X            }
  2978. X            if ($page =~ /Content-length:\s+/) {
  2979. X                $length = $';
  2980. X                if (&gotit("$savedir/$request", "$altdir/$request")
  2981. X                    && &length("$savedir/$request", "$altdir/$request") == $length) {
  2982. X                    next;
  2983. X                }
  2984. X            } else {
  2985. X                print "No content-length: $url\n";
  2986. X            }
  2987. X            # Skip if seen already:
  2988. X            if ($seen{$url}) { next; }
  2989. X            $seen{$url} = 1;
  2990. X
  2991. X            print STDERR "Requesting $url\n";
  2992. X            unless ($page = &url'get($url)) {
  2993. X                print "Can't get $url\n";
  2994. X                next;
  2995. X            } ;
  2996. X            &savefile($savedir . $request, $page);
  2997. X            &save_url($savedir . $request, $url);
  2998. X            print "(plain file)\n";
  2999. X        }
  3000. X        @toget = ();
  3001. X    }
  3002. X
  3003. X    print "\nSearch completed.\n";
  3004. X    close(STDOUT);
  3005. X    print STDERR "Result of exploration in $log\n";
  3006. X}
  3007. X
  3008. Xsub gotit {
  3009. X    # check if a file has been retrieved already
  3010. X    local ($path, $alt) = @_;
  3011. X
  3012. X    return 1 if (-e $path || -e $alt);
  3013. X    0;
  3014. X}
  3015. X
  3016. Xsub length {
  3017. X    local ($path, $alt) = @_;
  3018. X
  3019. X    return (stat($path))[7] if (-e $path);
  3020. X    return (stat($alt))[7] if (-e $alt);
  3021. X}
  3022. X
  3023. Xsub save_url {
  3024. X    # keep url-to-file mapping information
  3025. X    local ($path, $url) = @_;
  3026. X    local ($dir, $file);
  3027. X
  3028. X    ($dir, $file) = &basename($path);
  3029. X    ($url, $file) = &basename($url);
  3030. X    if (! -e "$dir/.url") {
  3031. X        open(URL, ">$dir/.url");
  3032. X        print URL "$url\n";
  3033. X        close(URL);
  3034. X    }
  3035. X}
  3036. X
  3037. Xsub savefile {
  3038. X    local ($path, $page) = @_;
  3039. X    local ($dir, $file);
  3040. X
  3041. X    ($dir, $file) = &basename($path);
  3042. X    # make directories if necessary, and write the page
  3043. X    if (! -d $dir) {
  3044. X        if (&mkdirhier($dir)) {
  3045. X            print "mkdir $dir\n";
  3046. X        } else {
  3047. X            print "Error in creating $dir: $!\n";
  3048. X        }
  3049. X    }
  3050. X    if ($path =~ m:/$:) {
  3051. X        # httpd may have mapped directory to a page,
  3052. X        # e.g, "/" -> "/foo/Welcome.html".
  3053. X        # as a workaround, we save it under some name
  3054. X        # unlikely to conflict.
  3055. X        $path .= "urlget_dir.html";
  3056. X    }
  3057. X    if (open(FILE, ">$path")) {
  3058. X        print FILE $page;
  3059. X        close(FILE);
  3060. X        print "got $path: ";
  3061. X    } else {
  3062. X        print "Error in creating $path: $!: ";
  3063. X    }
  3064. X}
  3065. X
  3066. Xsub loadfile {
  3067. X    local ($path) = @_;
  3068. X    local ($page);
  3069. X    local ($/);
  3070. X
  3071. X    if (open(FILE, "$path")) {
  3072. X        $page = <FILE>;
  3073. X        close(FILE);
  3074. X        $page;
  3075. X    } else {
  3076. X        print "Error in reading $path: $!\n";
  3077. X        undef;
  3078. X    }
  3079. X}
  3080. X
  3081. Xsub dump {
  3082. X    # dump @tocheck in a file so that htget can be resumed later.
  3083. X
  3084. X    open(DUMP, "> $dump");
  3085. X    print DUMP join("\n", @tocheck);
  3086. X    close(DUMP);
  3087. X}
  3088. X
  3089. Xsub sigint {
  3090. X    local ($/) = "\n";
  3091. X    local ($res);
  3092. X    print STDERR "Enter <CR> to continue, \"q\" to quit\n";
  3093. X    chop ($res = <STDIN>);
  3094. X    return if ($res eq "");
  3095. X    if ($res ne "q") {
  3096. X        print STDERR "Invalid response -- continuing\n";
  3097. X        return;
  3098. X    }
  3099. X    print STDERR "Quitting...\n";
  3100. X    &dump;        # dump @tocheck in a file.
  3101. X    print "\n\nInterrupted!\n";
  3102. X    close(STDOUT);
  3103. X    print STDERR "Result of exploration in $log\n";
  3104. X    exit(0);
  3105. X}
  3106. X
  3107. X# return a list of all the hrefs in a page
  3108. Xsub hrefs {
  3109. X    local($page) = @_;
  3110. X    $page =~ s/^[^<]+</</;
  3111. X    $page =~ s/>[^<]*</></g;
  3112. X    $page =~ s/>[^<]*$/>/g;
  3113. X    $page =~ s/<a[^>]*href\s*=\s*"([^"]+)"[^>]*>/$1\n/gi;
  3114. X    $page =~ s/<[^>]*>//g;
  3115. X    $page =~ s/\n+/\n/g;
  3116. X    split(/\n/,$page);
  3117. X}
  3118. X
  3119. X# return a list of all the embedded images in a page
  3120. Xsub srcs {
  3121. X    local($page) = @_;
  3122. X    $page =~ s/^[^<]+</</;
  3123. X    $page =~ s/>[^<]*</></g;
  3124. X    $page =~ s/>[^<]*$/>/g;
  3125. X    $page =~ s/<img[^>]*src\s*=\s*"([^"]+)"[^>]*>/$1\n/gi;
  3126. X    $page =~ s/<[^>]*>//g;
  3127. X    $page =~ s/\n+/\n/g;
  3128. X    split(/\n/,$page);
  3129. X}
  3130. X
  3131. X# Local Variables:
  3132. X# mode: cperl
  3133. X# cperl-indent-level: 8
  3134. X# cperl-continued-statement-offset: 8
  3135. X# End:
  3136. END_OF_FILE
  3137.   if test 12127 -ne `wc -c <'mosaic/htget.pl'`; then
  3138.     echo shar: \"'mosaic/htget.pl'\" unpacked with wrong size!
  3139.   fi
  3140.   chmod +x 'mosaic/htget.pl'
  3141.   # end of 'mosaic/htget.pl'
  3142. fi
  3143. if test -f 'mosaic/url.pl' -a "${1}" != "-c" ; then 
  3144.   echo shar: Will not clobber existing file \"'mosaic/url.pl'\"
  3145. else
  3146.   echo shar: Extracting \"'mosaic/url.pl'\" \(12077 characters\)
  3147.   sed "s/^X//" >'mosaic/url.pl' <<'END_OF_FILE'
  3148. X#! /bin/perl
  3149. X#
  3150. X# url.pl        --- recognize, parse and retrieve URLs
  3151. X#
  3152. X# This package contains:
  3153. X#
  3154. X# url'href:     identify URLs and turn them into hypertext links
  3155. X# url'get:      parse an URL and perform an http get
  3156. X# url'parse:    parse an URL and return ($type,$host,$port,$path,$request)
  3157. X# url'abs:      convert relative URLs to absolute ones
  3158. X# url'http:     perform an http request and return the result
  3159. X# url'gopher:   perform a gopher request and return the result
  3160. X# url'ftp:      perform an ftp request and return the result
  3161. X# 
  3162. X# Oscar Nierstrasz 26/8/93 oscar@cui.unige.ch
  3163. X#
  3164. X# 14/9/93 -- added url'gopher (not 100% stable) and url'ftp
  3165. X#
  3166. X# BUGS: relative paths work only if directories are always
  3167. X# terminated with a "/" -- otherwise assumes the directory is
  3168. X# just a filename and remembers the parent directory as the
  3169. X# current path.
  3170. X#
  3171. X# Can't get $! to return error messages properly.
  3172. X
  3173. Xpackage url;
  3174. X
  3175. Xrequire "sys/socket.ph";
  3176. X
  3177. X# unshift(@INC, "/homes/spaf/lib/perl");
  3178. X# unshift(@INC, "/user/u1/oscar/Cmd/PerlLib");
  3179. X
  3180. X# Gene Spafford's ftp package (and using the chat package).
  3181. X# Added ftp'grab -- a variant of ftp'get that returns its result
  3182. X# rather than writing to a local file.
  3183. Xrequire "ftplib.pl";
  3184. X
  3185. X$user = getlogin;
  3186. X
  3187. X# locals:
  3188. X$type = undef;
  3189. X$host = undef;
  3190. X$port = undef;
  3191. X$path = undef;
  3192. X$request = undef;
  3193. X
  3194. X$sockaddr = 'S n a4 x8';
  3195. Xchop($thishost = `hostname`);
  3196. X($name, $aliases, $proto) = getprotobyname("tcp");
  3197. X($name, $aliases, $type, $len, $thisaddr) = gethostbyname($thishost);
  3198. X$thissock = pack($sockaddr, &AF_INET, 0, $thisaddr);
  3199. X
  3200. X# Try to recognize URLs and ftp file indentifiers and convert them into HREFs:
  3201. X# This routine is evolving.  The patterns are not perfect.
  3202. X# This is really a parsing problem, and not a job for perl ...
  3203. X# It is also generally impossible to distinguish ftp site names
  3204. X# from newsgroup names if the ":<directory>" is missing.
  3205. X# An arbitrary file name ("runtime.pl") can also be confused.
  3206. Xsub href {
  3207. X        # study; # doesn't speed things up ...
  3208. X
  3209. X        # to avoid special cases for beginning & end of line
  3210. X        s|^|#|; s|$|#|;
  3211. X
  3212. X        # URLS: <serice>:<rest-of-url>
  3213. X        s|(news:[\w.]+)|<A HREF="$&">$&</A>|g;
  3214. X        s|(http:[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3215. X        s|(file:[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3216. X        s|(ftp:[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3217. X        s|(wais:[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3218. X        s|(gopher:[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3219. X        s|(telnet:[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3220. X        # s|(\w+://[\w/.:+\-]+)|<A HREF="$&">$&</A>|g;
  3221. X
  3222. X        # catch some newsgroups to avoid confusion with sites:
  3223. X        s|([^\w\-/.:@>])(alt\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3224. X        s|([^\w\-/.:@>])(bionet\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3225. X        s|([^\w\-/.:@>])(bit\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3226. X        s|([^\w\-/.:@>])(comp\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3227. X        s|([^\w\-/.:@>])(gnu\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3228. X        s|([^\w\-/.:@>])(misc\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3229. X        s|([^\w\-/.:@>])(news\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3230. X        s|([^\w\-/.:@>])(rec\.[\w.+\-]+[\w+\-]+)|$1<A HREF="news:$2">$2</A>|g;
  3231. X
  3232. X        # FTP locations (with directory):
  3233. X        # anonymous@<site>:<path>
  3234. X        s|(anonymous@)([a-zA-Z][\w.+\-]+\.[a-zA-Z]{2,}):(\s*)([\w\d+\-/.]+)|$1<A HREF="file://$2/$4">$2:$4</A>$3|g;
  3235. X        # ftp@<site>:<path>
  3236. X        s|(ftp@)([a-zA-Z][\w.+\-]+\.[a-zA-Z]{2,}):(\s*)([\w\d+\-/.]+)|$1<A HREF="file://$2/$4">$2:$4</A>$3|g;
  3237. X        # <site>:<path>
  3238. X        s|([^\w\-/.:@>])([a-zA-Z][\w.+\-]+\.[a-zA-Z]{2,}):(\s*)([\w\d+\-/.]+)|$1<A HREF="file://$2/$4">$2:$4</A>$3|g;
  3239. X        # NB: don't confuse an http server with a port number for
  3240. X        # an FTP location!
  3241. X        # internet number version: <internet-num>:<path>
  3242. X        s|([^\w\-/.:@])(\d{2,}\.\d{2,}\.\d+\.\d+):([\w\d+\-/.]+)|$1<A HREF="file://$2/$3">$2:$3</A>|g;
  3243. X
  3244. X        # just the site name (assume two dots): <site>
  3245. X        s|([^\w\-/.:@>])([a-zA-Z][\w+\-]+\.[\w.+\-]+\.[a-zA-Z]{2,})([^\w\d\-/.:!])|$1<A HREF="file://$2">$2</A>$3|g;
  3246. X        # NB: can be confused with newsgroup names!
  3247. X        # <site>.com has only one dot:
  3248. X        s|([^\w\-/.:@>])([a-zA-Z][\w.+\-]+\.com)([^\w\-/.:])|$1<A HREF="file://$2">$2</A>$3|g;
  3249. X
  3250. X        # just internet numbers:
  3251. X        s|([^\w\-/.:@])(\d+\.\d+\.\d+\.\d+)([^\w\-/.:])|$1<A HREF="file://$2">$2</A>$3|g;
  3252. X        # unfortunately inet numbers can easily be confused with
  3253. X        # european telephone numbers ...
  3254. X
  3255. X        s|^#||; s|#$||;
  3256. X}
  3257. X
  3258. X# parse an URL, issue the request and return the result
  3259. Xsub get {
  3260. X        local($url,$version) = @_;
  3261. X        ($type,$host,$port,$path,$request) = &parse($type,$host,$port,$path,$url);
  3262. X        if ($host) {
  3263. X                if ($type eq "http") { &http($host,$port,$request,$version); }
  3264. X                elsif ($type eq "gopher") { &gopher($host,$port,$request); }
  3265. X                elsif ($type eq "ftp") { &ftp($host,$request); }
  3266. X                else { print STDERR "url'get: $type requests unimplemented\n"; }
  3267. X        }
  3268. X        else {
  3269. X                undef;
  3270. X        }
  3271. X}
  3272. X
  3273. X# convert an URL to ($type,host,port,path,request)
  3274. X# given previous type, host, port and path, will handle relative URLs
  3275. X# NB: May need special processing for different service types (e.g., news)
  3276. Xsub parse {
  3277. X        local($type,$host,$port,$path,$url) = @_;
  3278. X        if ($url =~ m|^(\w+)://(.*)|) {
  3279. X                $type = $1;
  3280. X                $host = $2;
  3281. X                $port = &defport($type);
  3282. X                $request = "/"; # default
  3283. X                ($host =~ s|^([^/]+)(/.*)$|$1|) && ($request = $2);
  3284. X                ($host =~ s/:(\d+)$//) && ($port = $1);
  3285. X                ($path = $request) =~ s|[^/]*$||;
  3286. X        }
  3287. X        else {
  3288. X                # relative URL of form "<type>:<request>"
  3289. X                if ($url =~ /^(\w+):(.*)/) {
  3290. X                        $type = $1;
  3291. X                        $request = $2;
  3292. X                }
  3293. X                # relative URL of form "<request>"
  3294. X                else { $request = $url; }
  3295. X                $request =~ s|^$|/|;
  3296. X                $request =~ s|^([^/])|$path$1|; # relative path
  3297. X                $request =~ s|/\./|/|g;
  3298. X                while ($request =~ m|/\.\./|) {
  3299. X                        $request =~ s|[^/]*/\.\./||;
  3300. X                }
  3301. X        # file:/path and wwfs:/path does not need host & port.
  3302. X#                 # assume previous host & port:
  3303. X#                 unless ($host) {
  3304. X#                         # $! = "url'parse: no host for $url\n";
  3305. X#                         print STDERR "url'parse: no host for $url\n";
  3306. X#                         return (undef,undef,undef,undef,undef);
  3307. X#                 }
  3308. X        }
  3309. X        ($type,$host,$port,$path,$request);
  3310. X}
  3311. X
  3312. X# convert relative http URLs to absolute ones:
  3313. X# should be patched to handle HREFs w/o double quotes ...
  3314. X# also need to handle inlined images!
  3315. Xsub abs {
  3316. X        local($url,$page) = @_;
  3317. X        ($type,$host,$port,$path,$request) = &parse(undef,undef,undef,undef,$url);
  3318. X        $root = "http://$host:$port";
  3319. X        @hrefs = split(/<[Aa]/,$page);
  3320. X        $n = $[;
  3321. X        while (++$n <= $#hrefs) {
  3322. X                # absolute URLs ok:
  3323. X                ($hrefs[$n] =~ m|href\s*=\s*"http://|i) && next;
  3324. X                ($hrefs[$n] =~ m|href\s*=\s*"\w+:|i) && next;
  3325. X        # relative URL without "scheme"
  3326. X                ($hrefs[$n] =~ s|href\s*=\s*"//([^"]*)"|HREF="http:$1"|i) && next;
  3327. X                # relative URL from root:
  3328. X                ($hrefs[$n] =~ s|href\s*=\s*"/([^"]*)"|HREF="$root/$1"|i) && next;
  3329. X                ($hrefs[$n] =~ s|href\s*=\s*/([^>]*)>|HREF=$root/$1>|i) && next;
  3330. X                # relative from $path:
  3331. X                $hrefs[$n] =~ s|href\s*=\s*"([^/"][^"]*)"|HREF="$root$path$1"|i;
  3332. X                $hrefs[$n] =~ s|href\s*=\s*([^/">][^>]*)>|HREF=$root$path$1>|i;
  3333. X                # collapse relative paths:
  3334. X                $hrefs[$n] =~ s|/\./|/|g;
  3335. X                while ($hrefs[$n] =~ m|/\.\./|) {
  3336. X                        $hrefs[$n] =~ s|[^/]*/\.\./||;
  3337. X                }
  3338. X        }
  3339. X        join("<A",@hrefs);
  3340. X}
  3341. X
  3342. X# perform an http request and return the result
  3343. X# Code adapted from Marc van Heyningen
  3344. Xsub http {
  3345. X        local($host,$port,$request,$version) = @_;
  3346. X        ($fqdn, $aliases, $type, $len, $thataddr) = gethostbyname($host);
  3347. X        $that = pack($sockaddr, &AF_INET, $port, $thataddr);
  3348. X        socket(FS, &AF_INET, &SOCK_STREAM, $proto) || return undef;
  3349. X        bind(FS, $thissock) || return undef;
  3350. X        local($/);
  3351. X        unless (eval q!
  3352. X                $SIG{'ALRM'} = "url'timeout";
  3353. X                alarm(30);
  3354. X                connect(FS, $that) || return undef;
  3355. X                select(FS); $| = 1; select(STDOUT);
  3356. X                # NB: Need extra \n to terminate MIME header:
  3357. X                if ($version) { print FS "GET $request HTTP/1.0\r\n\n"; }
  3358. X                else { print FS "GET $request\r\n"; }
  3359. X                $page = <FS>; 
  3360. X                $SIG{'ALRM'} = "IGNORE";
  3361. X                !) {
  3362. X                        return undef;
  3363. X                }
  3364. X        close(FS);
  3365. X        # With HTTP/1.0 would include MIME header
  3366. X        $page;
  3367. X}
  3368. X
  3369. X# perform an http HEAD request and return the result
  3370. Xsub http_head {
  3371. X        local($host,$port,$request) = @_;
  3372. X        ($fqdn, $aliases, $type, $len, $thataddr) = gethostbyname($host);
  3373. X        $that = pack($sockaddr, &AF_INET, $port, $thataddr);
  3374. X        socket(FS, &AF_INET, &SOCK_STREAM, $proto) || return undef;
  3375. X        bind(FS, $thissock) || return undef;
  3376. X        local($/);
  3377. X        unless (eval q!
  3378. X                $SIG{'ALRM'} = "url'timeout";
  3379. X                alarm(30);
  3380. X                connect(FS, $that) || return undef;
  3381. X                select(FS); $| = 1; select(STDOUT);
  3382. X                # NB: Need extra \n to terminate MIME header:
  3383. X                print FS "HEAD $request HTTP/1.0\r\n\n";
  3384. X                $page = <FS>; 
  3385. X                $SIG{'ALRM'} = "IGNORE";
  3386. X                !) {
  3387. X                        return undef;
  3388. X                }
  3389. X        close(FS);
  3390. X        # With HTTP/1.0 would include MIME header
  3391. X        $page;
  3392. X}
  3393. X
  3394. X# This doesn't always work -- gopher URLs sometimes contain
  3395. X# a leading file type in the pathname which must be stripped off.
  3396. X# needs work.  URLs may also contain blanks, tabs and other nasties.
  3397. X# IS THIS THE RIGHT PROTOCOL FOR GOPHER???
  3398. Xsub gopher {
  3399. X        local($host,$port,$request) = @_;
  3400. X        ($fqdn, $aliases, $type, $len, $thataddr) = gethostbyname($host);
  3401. X        $that = pack($sockaddr, &AF_INET, $port, $thataddr);
  3402. X        socket(FS, &AF_INET, &SOCK_STREAM, $proto) || return undef;
  3403. X        bind(FS, $thissock) || return undef;
  3404. X        # gopher doesn't need leading "/":
  3405. X        $request =~ s|^/||;
  3406. X#        # try to strip off the gopher type ...
  3407. X#        ($request =~ s|^([I]?\d+)/||) && ($gtype = $1);
  3408. X        local($/);
  3409. X        unless (eval q!
  3410. X                $SIG{'ALRM'} = "url'timeout";
  3411. X                alarm(30);
  3412. X                connect(FS, $that) || return undef;
  3413. X                select(FS); $| = 1; select(STDOUT);
  3414. X                print FS "$request\r\n";
  3415. X                print STDERR "Gopher: $request\n"; # debug
  3416. X                $page = <FS>; 
  3417. X                $SIG{'ALRM'} = "IGNORE";
  3418. X                !) {
  3419. X                        return undef;
  3420. X                }
  3421. X        close(FS);
  3422. X        # This return value will also contain a leading type field.
  3423. X        # Should be stripped off by the calling routine ...
  3424. X        $page;
  3425. X}
  3426. X
  3427. X# ftp'grab is a version of ftp'get that returns the page
  3428. X# retrieved rather than writing it to a local file.
  3429. X# Perhaps not so nice for big files, but what the heck.
  3430. Xsub ftp {
  3431. X        local($host,$file) = @_;
  3432. X        &ftp'open($host, "ftp", "$user@$thishost") || &fail;
  3433. X        &ftp'type("i") || &fail;
  3434. X        $page = &ftp'grab($file) || &fail;
  3435. X        &ftp'close;
  3436. X        $page;
  3437. X}
  3438. X
  3439. Xsub fail {
  3440. X        $save = &ftp'error;
  3441. X        &ftp'close;
  3442. X        die $save;
  3443. X}
  3444. X
  3445. Xsub timeout { die "Timeout\n"; }
  3446. X
  3447. X# default ports
  3448. Xsub defport {
  3449. X        local($type) = @_;
  3450. X        if ($type eq "http") { 80; }
  3451. X        elsif ($type eq "gopher") { 70; }
  3452. X        else { undef; }
  3453. X}
  3454. X
  3455. X1;
  3456. X
  3457. END_OF_FILE
  3458.   if test 12077 -ne `wc -c <'mosaic/url.pl'`; then
  3459.     echo shar: \"'mosaic/url.pl'\" unpacked with wrong size!
  3460.   fi
  3461.   # end of 'mosaic/url.pl'
  3462. fi
  3463. echo shar: End of archive 13 \(of 22\).
  3464. cp /dev/null ark13isdone
  3465. MISSING=""
  3466. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  3467.     if test ! -f ark${I}isdone ; then
  3468.     MISSING="${MISSING} ${I}"
  3469.     fi
  3470. done
  3471. if test "${MISSING}" = "" ; then
  3472.     echo You have unpacked all 22 archives.
  3473.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  3474. else
  3475.     echo You still must unpack the following archives:
  3476.     echo "        " ${MISSING}
  3477. fi
  3478. exit 0
  3479. exit 0 # Just in case...
  3480.