home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / protocol / appletal / 4327 < prev    next >
Encoding:
Internet Message Format  |  1993-01-05  |  38.4 KB

  1. Path: sparky!uunet!news.larc.nasa.gov!teb.larc.nasa.gov!caywood
  2. From: caywood@teb.larc.nasa.gov (John Caywood)
  3. Newsgroups: comp.protocols.appletalk
  4. Subject: Re: Dumping Mac disks to unix hosted tape (long)
  5. Date: 5 Jan 1993 19:58:27 GMT
  6. Organization: NASA Langley Research Center, Hampton, VA  USA
  7. Lines: 1251
  8. Distribution: world
  9. Message-ID: <1icp93INNoen@rave.larc.nasa.gov>
  10. References: <1hnmj6INNb8l@rave.larc.nasa.gov>
  11. NNTP-Posting-Host: teb.larc.nasa.gov
  12. Keywords: dump backup
  13.  
  14. In article <1hnmj6INNb8l@rave.larc.nasa.gov>, caywood@teb.larc.nasa.gov (John Caywood) writes:
  15. |> I'm looking for a Macintosh network backup solution.  I have a 150M tape
  16. |> and a 2.3G tape on a Sun SPARC 2, but no good way to dump Macs to either
  17. |> tape.  I have MacDumper v3.2, but this version only dumps to disk, not
  18. |> to tape, and has some other limitations.  Just checked rutgers.edu and
  19. |> found that pub/src/macdump.tar.Z is older than the version I have, dating
  20. |> from (mostly) July, 1989.  Got my version from a friend who no longer
  21. |> works here, so I don't know the source but files are dated Sept. 1990
  22. |> and Feb. 1991.  Is there a newer version somewhere?
  23. |> 
  24.  
  25. I have two partial solutions so far.  Thanks to Steve Faull
  26. (steve@neopath.wa.com) and Dave Platt (dplatt@ntg.com) for pointing me
  27. to bbn.com as the source for MacDump.  I got the source on 12/29/92 and
  28. compiled it with only minor problems; used mcvert and capit (from
  29. cap60/contrib/AufsTools) to convert the Dumper.Hqx and Restore.Hqx
  30. files from BBN, and it works.  The current versions are Dumper 3.3 and
  31. Restore 2.3.
  32.  
  33. Dave Platt also sent patches to macdump.c to enable macdump to write
  34. directly to tape, to verify a dump tape, and to extract the dump file
  35. back to a UNIX disk.  Hence the "partial solution".  In Dave's words
  36.  
  37.     There is not, currently, any way to do a "selective" restore from the
  38.     tape dump to Unix disk - you must read back the whole tape, create a
  39.     macrestore-compatible full-dump file, and then restore portions of it to
  40.     the Mac over the network by using Restore.  Maybe someday I'll get
  41.     around to adding the ability to extract selected files from the
  42.     tape-dump and write them to Unix disk in CAP/Aufs or AppleSingle or
  43.     MacBinary format.
  44.  
  45. Dave's dump-to-tape patches work; I've only done a few tests so far, but I
  46. was able to successfully restore to a Mac files that had been dumped to
  47. tape with Dave's enhanced macdump.  I sent a reply to Dave, but haven't
  48. heard from him on how we can distribute his patches.
  49.  
  50. Nigel Gilbert (Nigel.Gilbert@soc.surrey.ac.uk) sent a different partial
  51. solution.  He modified macdump to accept a -directory=folder_name option
  52. so that you can dump just one folder from a Macintosh volume -- another
  53. useful feature.  It appears that Nigel's modifications are to an earlier
  54. version of macdump, not the current version at bbn.com, so merging his
  55. modifications with Dave's is not straightforward.  Nigel agreed to let me
  56. post his modifications, but the file is large and not suitable for posting.
  57.  
  58. The latest README for the MacDump distribution on bbn.com asserts that no
  59. further updates will be released by BBN.  Judging from the 7 email requests
  60. I received requesting that I post this summary, there's a clear need for
  61. these improvements.  I have enclosed Dave Platt's patches, plus my own
  62. patch to the macdump man page documenting the changes, but I prefer not to
  63. volunteer to maintain the package.  Is anyone else willing?  Any other
  64. suggestions on maintaining and distributing these improvements?
  65.  
  66. Thanks to all who replied.
  67.  
  68.   ==================================================================
  69. >From dplatt@ntg.com Mon Dec 28 20:13:33 1992
  70. >From: dplatt@ntg.com (Dave Platt)
  71. Date: Mon, 28 Dec 1992 17:05:53 PST
  72. X-Mailer: Mail User's Shell (7.1.1 5/02/90)
  73. To: caywood@teb.larc.nasa.gov
  74. Subject: Macintosh dump-to-tape
  75. Content-Length: 30643
  76.  
  77. If you apply the following diffs to the most recent version of macdump
  78. (the one currently on bbn.com) you'll get the ability to dump
  79. directly from a Mac to tape (bypassing the Unix-disk stage).
  80.  
  81. The modified macdump accepts the -tape, -read, -verify, and -blocks
  82. commands.  "-tape" means that it should spool the dump session (the
  83. AppleTalk packet stream, essentially) to standard-output rather than
  84. writing a disk file.  "-read" means that it should read the packet
  85. stream from standard input and create a dump file which can be processed
  86. by the macrestore daemon.  "-verify" means that it should simply verify
  87. the input stream rather than creating a dumpfile.  "-blocks" specifies
  88. the number of 512-byte blocks per write to standard-out.
  89.  
  90. You can dump to tape in either of two ways:  direct to the device,
  91. or via a pipe to "dd".  The latter method a bit more complex but
  92. may give better performance, as it allows dd to be writing one block
  93. to tape while macdump is filling another block over the network.
  94.  
  95. For example:
  96.  
  97.     macdump -mac=joe -disk=Big -full -tape -blocks=20 | \
  98.       dd ibs=20b obs=200b of=/dev/rst9
  99.  
  100. Then, to create a macrestore-compatible file:
  101.  
  102.     dd if=/dev/rst9 ibs=200b obs=20b | \
  103.        macdump -mac=joe -user=joe -read
  104.  
  105. There is not, currently, any way to do a "selective" restore from the
  106. tape dump to Unix disk - you must read back the whole tape, create a
  107. macrestore-compatible full-dump file, and then restore portions of it to
  108. the Mac over the network by using Restore.  Maybe someday I'll get
  109. around to adding the ability to extract selected files from the
  110. tape-dump and write them to Unix disk in CAP/Aufs or AppleSingle or
  111. MacBinary format.
  112.  
  113. #! /bin/sh
  114. # This is a shell archive.  Remove anything before this line, then unpack
  115. # it by saving it into a file and typing "sh file".  To overwrite existing
  116. # files, type "sh file -c".  You can also feed this as standard input via
  117. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  118. # will see the following message at the end:
  119. #        "End of shell archive."
  120. # Contents:  Makefile.diff macdump.c.diff
  121. # Wrapped by dplatt@ntg on Mon Dec 28 16:58:12 1992
  122. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  123. if test -f 'Makefile.diff' -a "${1}" != "-c" ; then 
  124.   echo shar: Will not clobber existing file \"'Makefile.diff'\"
  125. else
  126. echo shar: Extracting \"'Makefile.diff'\" \(922 characters\)
  127. sed "s/^X//" >'Makefile.diff' <<'END_OF_FILE'
  128. X*** macdump-bbn/Makefile    Thu Feb 21 13:12:01 1991
  129. X--- macdump-merge/Makefile    Wed Jun 24 14:15:41 1992
  130. X***************
  131. X*** 6,11 ****
  132. X--- 6,12 ----
  133. X  LIBDIR = /usr/local/lib/cap
  134. X  BINDIR = /usr/local/bin
  135. X  OPERDIR = /usr/ucc/bin
  136. X+ DUMPFLAGS = -DDOUBLEBUFFER
  137. X  # define this if you want to have a special user that is allowed in with no 
  138. X  # password. This if all dumps are stored under a single user name (and if
  139. X  # security is not a problem).
  140. X***************
  141. X*** 39,45 ****
  142. X      $(LD) macdump.o print_rec.o $(LDFLAGS)
  143. X  
  144. X  macdump.o:    macdump.c macdump.h /usr/include/netat/appletalk.h
  145. X!     $(CC) $(CFLAGS) macdump.c 
  146. X  
  147. X  print_rec.o:    print_rec.c macdump.h
  148. X      $(CC) $(CFLAGS) print_rec.c
  149. X--- 40,46 ----
  150. X      $(LD) macdump.o print_rec.o $(LDFLAGS)
  151. X  
  152. X  macdump.o:    macdump.c macdump.h /usr/include/netat/appletalk.h
  153. X!     $(CC) $(CFLAGS) $(DUMPFLAGS) macdump.c 
  154. X  
  155. X  print_rec.o:    print_rec.c macdump.h
  156. X      $(CC) $(CFLAGS) print_rec.c
  157. END_OF_FILE
  158. if test 922 -ne `wc -c <'Makefile.diff'`; then
  159.     echo shar: \"'Makefile.diff'\" unpacked with wrong size!
  160. fi
  161. # end of 'Makefile.diff'
  162. fi
  163. if test -f 'macdump.c.diff' -a "${1}" != "-c" ; then 
  164.   echo shar: Will not clobber existing file \"'macdump.c.diff'\"
  165. else
  166. echo shar: Extracting \"'macdump.c.diff'\" \(25771 characters\)
  167. sed "s/^X//" >'macdump.c.diff' <<'END_OF_FILE'
  168. X*** macdump-bbn/macdump.c    Tue Aug  7 10:51:14 1990
  169. X--- macdump-merge/macdump.c    Fri Aug 21 16:31:36 1992
  170. X***************
  171. X*** 42,55 ****
  172. X--- 42,66 ----
  173. X  
  174. X  /* Definitions */
  175. X  #include <stdio.h>
  176. X+ #include <malloc.h>
  177. X  #include <sys/types.h>
  178. X  #include <sys/file.h>
  179. X  #include <pwd.h>
  180. X  #include <netat/appletalk.h>
  181. X  #include <time.h>
  182. X+ #include <sys/time.h>
  183. X  #include <assert.h>
  184. X  #include <sys/stat.h>
  185. X  
  186. X+ #ifdef DOUBLEBUFFER
  187. X+ # include <sys/asynch.h>
  188. X+ # include <unistd.h>
  189. X+ # include <sys/filio.h>
  190. X+ # include <fcntl.h>
  191. X+ # include <signal.h>
  192. X+ # include <errno.h>
  193. X+ #endif
  194. X+ 
  195. X  #include "macdump.h"
  196. X  #include "dumpprotocol.h"
  197. X  
  198. X***************
  199. X*** 67,72 ****
  200. X--- 78,88 ----
  201. X  int forcefull = 0;        /* true to force a full dump */
  202. X  int forceincr = 0;        /* true to force an incremental */
  203. X  int getdisknames = 0;        /* true to find volume names */
  204. X+ int tapewrite = 0;              /* true if writing to tape rather than disk */
  205. X+ int taperead = 0;               /* true if reading tape */
  206. X+ int verify = 0;
  207. X+ int istape = 0;
  208. X+ time_t timenow;
  209. X  char *progname;
  210. X  AddrBlock macaddr;        /* address of macintosh to dump */
  211. X  ABusRecord abr;            /* record for remote access */
  212. X***************
  213. X*** 90,95 ****
  214. X--- 106,138 ----
  215. X  char fullname[256];
  216. X  char *dumpname;
  217. X  char tmpname[256];
  218. X+ char tapeheader[256];
  219. X+ char magicheader[] = "!macdumptape0";
  220. X+ 
  221. X+ #define BYTESPERBLOCK 512
  222. X+ 
  223. X+ #ifndef TAPEBUFFERSIZE
  224. X+ # define TAPEBUFFERSIZE 10*BYTESPERBLOCK
  225. X+ #endif
  226. X+ 
  227. X+ char *tapebuffer;
  228. X+ int tapebuffersize = TAPEBUFFERSIZE;
  229. X+ int tapebuffercount;
  230. X+ int tapebufferavail;
  231. X+ 
  232. X+ #ifdef DOUBLEBUFFER
  233. X+ char *writebuffer;
  234. X+ aio_result_t write_result;
  235. X+ int write_in_progress;
  236. X+ int write_completed;
  237. X+ int write_offset;
  238. X+ int write_trace;
  239. X+ void wait_for_io();
  240. X+ extern int aiowrite();
  241. X+ extern aio_result_t *aiowait();
  242. X+ #endif
  243. X+ 
  244. X+ 
  245. X  #define TMPNAME "TMPXXXXXX"
  246. X  
  247. X  #include "dumperrors.h"
  248. X***************
  249. X*** 96,101 ****
  250. X--- 139,147 ----
  251. X  
  252. X  char *CtoPStr(), *PtoCStr();
  253. X  
  254. X+ void initbuffer();
  255. X+ void flushbuffer();
  256. X+ 
  257. X  main(argc, argv) char **argv;
  258. X  {
  259. X    EntityName en;
  260. X***************
  261. X*** 105,110 ****
  262. X--- 151,157 ----
  263. X    time_t now;
  264. X    struct tm *tmnow, *localtime();
  265. X    int err;
  266. X+   int i;
  267. X    struct stat fullstatb, incrstatb;
  268. X    char *strcpy();
  269. X    char *p;
  270. X***************
  271. X*** 134,139 ****
  272. X--- 181,208 ----
  273. X        forceincr = 1;
  274. X      else if (strcmp(*argv, "-disknames", 3) == 0)
  275. X        getdisknames = 1;
  276. X+     else if (strncmp(*argv, "-tape", 5) == 0)
  277. X+       tapewrite = 1;
  278. X+     else if (strncmp(*argv, "-read", 5) == 0)
  279. X+       taperead = 1;
  280. X+     else if (strncmp(*argv, "-blocks=", 8) == 0) {
  281. X+       i = atoi(*argv+8);
  282. X+       if (i > 0 && i <= 9999) {
  283. X+     tapebuffersize = i * BYTESPERBLOCK;
  284. X+       } else {
  285. X+     fprintf(stderr, "%s: blocks must be between 1 and 9999\n", progname);
  286. X+     clean_exit(EXIT_USER);
  287. X+       }
  288. X+     }
  289. X+     else if (strncmp(*argv, "-verify", 5) == 0) {
  290. X+       taperead = 1;
  291. X+       verify = 1;
  292. X+     }
  293. X+ #ifdef DOUBLEBUFFER
  294. X+     else if (strncmp(*argv, "-writetrace", 11) == 0) {
  295. X+       write_trace = 1;
  296. X+     }
  297. X+ #endif
  298. X      else if (strncmp(*argv, "-d", 2) == 0) {
  299. X        ++debug;
  300. X        if (*argv+2 != '\0') dbugarg(*argv+2);
  301. X***************
  302. X*** 147,182 ****
  303. X    if (macname == 0)
  304. X      macname = user;
  305. X  
  306. X    if (!getdisknames) {
  307. X!     if (disk == 0 && directory == 0) {
  308. X        fprintf(stderr, "%s: you must specify a disk volume or directory\n",
  309. X            progname);
  310. X        clean_exit(EXIT_USER);
  311. X      }
  312. X! 
  313. X!     if ((pwd = getpwnam(user)) == 0) {
  314. X!       fprintf(stderr, "%s: unknown user %s\n", progname, user);
  315. X!       clean_exit(EXIT_SETUP);
  316. X      }
  317. X!     if (chdir(pwd->pw_dir) < 0) {
  318. X!       fprintf(stderr, "%s: failed to connect to directory %s\n", pwd->pw_dir);
  319. X!       clean_exit(EXIT_SETUP);
  320. X      }
  321. X-     if (chdir("macdumps") < 0) {
  322. X-       fprintf(stderr, "%s: %s has no 'macdumps' directory\n", progname, user);
  323. X-       clean_exit(EXIT_SETUP);
  324. X-     }
  325. X  
  326. X-     /* Run as this user */
  327. X-     setgid(pwd->pw_gid);
  328. X-     setuid(pwd->pw_uid);
  329. X- 
  330. X-     /* Decide whether we are doing a full or an incremental */
  331. X-     strcpy(tmpname, TMPNAME);
  332. X-     mktemp(tmpname);        /* temp storage */
  333. X- 
  334. X    }
  335. X  
  336. X    /* Upper case the mac and disk names */
  337. X    for(p = macname; *p; ++p)
  338. X      if (*p >= 'a' && *p <= 'z') *p -= ' ';
  339. X--- 216,266 ----
  340. X    if (macname == 0)
  341. X      macname = user;
  342. X  
  343. X+   if (taperead && tapewrite) {
  344. X+     fprintf(stderr, "Cannot both read and write tape at once!\n");
  345. X+     clean_exit(EXIT_USER);
  346. X+   }
  347. X+ 
  348. X+   istape = taperead | tapewrite;
  349. X+ 
  350. X    if (!getdisknames) {
  351. X!     if (!verify && (disk == 0 && directory == 0)) {
  352. X        fprintf(stderr, "%s: you must specify a disk volume or directory\n",
  353. X            progname);
  354. X        clean_exit(EXIT_USER);
  355. X      }
  356. X!     
  357. X!     if (!istape) {
  358. X!       if ((pwd = getpwnam(user)) == 0) {
  359. X!     fprintf(stderr, "%s: unknown user %s\n", progname, user);
  360. X!     clean_exit(EXIT_SETUP);
  361. X!       }
  362. X!       if (chdir(pwd->pw_dir) < 0) {
  363. X!     fprintf(stderr, "%s: failed to connect to directory %s\n", pwd->pw_dir);
  364. X!     clean_exit(EXIT_SETUP);
  365. X!       }
  366. X!       if (chdir("macdumps") < 0) {
  367. X!     fprintf(stderr, "%s: %s has no 'macdumps' directory\n", progname, user);
  368. X!     clean_exit(EXIT_SETUP);
  369. X!       }
  370. X!       
  371. X!       /* Run as this user */
  372. X!       setgid(pwd->pw_gid);
  373. X!       setuid(pwd->pw_uid);
  374. X      }
  375. X!     
  376. X!     /* Decide whether we are doing a full or an incremental */
  377. X!     if (verify) {
  378. X!       strcat(tmpname, "/dev/null");
  379. X!     } else {
  380. X!       strcpy(tmpname, TMPNAME);
  381. X!       mktemp(tmpname);        /* temp storage */
  382. X      }
  383. X  
  384. X    }
  385. X  
  386. X+   initbuffer();
  387. X+ 
  388. X    /* Upper case the mac and disk names */
  389. X    for(p = macname; *p; ++p)
  390. X      if (*p >= 'a' && *p <= 'z') *p -= ' ';
  391. X***************
  392. X*** 223,317 ****
  393. X        full = 0;
  394. X      }
  395. X  
  396. X!     fprintf(stderr, "Doing %s dump to %s\n",
  397. X!         directory == 0 ? (full ? "full" : "incremental") : "directory",
  398. X!         dumpname);
  399. X    }
  400. X  
  401. X    /* Init appletalk */
  402. X!   abInit(debug);
  403. X! 
  404. X!   /* Look up the macintosh */
  405. X!   nbpInit();
  406. X!   strcpy(&en.objStr, macname);
  407. X!   strcpy(&en.typeStr, "DUMPDEV");
  408. X!   strcpy(&en.zoneStr, zone);
  409. X! 
  410. X!   nbpr.nbpRetransmitInfo.retransInterval = 8;
  411. X!   nbpr.nbpRetransmitInfo.retransCount = 20;
  412. X!   nbpr.nbpBufPtr = nbpt;
  413. X!   nbpr.nbpBufSize = sizeof(nbpt);
  414. X!   nbpr.nbpDataField = 1;
  415. X!   nbpr.nbpEntityPtr = &en;
  416. X!   err = NBPLookup(&nbpr, FALSE);
  417. X!   if (err != noErr || nbpr.nbpDataField <= 0) {
  418. X!     fprintf(stderr, "NBP Lookup of %s failed\n", macname);
  419. X!     clean_exit(EXIT_NOMAC);
  420. X!   }
  421. X!   /* Extract the first item */
  422. X!   NBPExtract(nbpt, nbpr.nbpDataField, 1, &en, &macaddr);
  423. X!   
  424. X!   /* No longer need the NBP socket */
  425. X!   nbpShutdown();
  426. X! 
  427. X!   if (debug)
  428. X      printf("Dump device at %d/%d:%02x\n", htons(macaddr.net), macaddr.node,
  429. X!      macaddr.skt);
  430. X  
  431. X!   if (getdisknames) {
  432. X!     int gotname = 0;
  433. X!     register int i;
  434. X!     struct VolNameRecord *vnp;
  435. X! 
  436. X!     for(i = 1; ; ++i) {
  437. X!       register short *ip = (short *)buffer;
  438. X!       *ip = htons(i);
  439. X! 
  440. X!       if (send_cmd(VOLUME_NAME, buffer, sizeof(short)) != ACK) {
  441. X!     if (!gotname) 
  442. X!       /* convert response to a C string */
  443. X!       fprintf(stderr, "%s: Response: %s\n", progname, PtoCStr(recbuffer));
  444. X!     break;
  445. X        }
  446. X!       gotname = 1;
  447. X!       vnp = (struct VolNameRecord *)recbuffer;
  448. X!       printf("Volume index %d, disk=\"%s\" %dMB\n", i,
  449. X!          PtoCStr(vnp->volname), htonl(vnp->size)/(1024*1024));
  450. X      }
  451. X! 
  452. X!     /* Have seen all volumes */
  453. X!     clean_exit(EXIT_OK);
  454. X    }
  455. X  
  456. X!   /* Try to access the right disk volume on the mac */
  457. X!   if (directory != 0) {
  458. X!     buffer[0] = strlen(directory);
  459. X!     strcpy(&buffer[1], directory);
  460. X    } else {
  461. X!     buffer[0] = strlen(disk);
  462. X!     strcpy(&buffer[1], disk);
  463. X    }
  464. X-   if (send_cmd(directory == 0 ? 
  465. X-            (full ? BEGIN_FULL : BEGIN_INCR) : BEGIN_DIRECTORY,
  466. X-            buffer, buffer[0]+1) != ACK) {
  467. X-     /* convert response to a C string */
  468. X-     fprintf(stderr, "%s: Failed to dump %s. Response: %s\n", progname,
  469. X-         directory == 0 ? disk : directory, PtoCStr(recbuffer));
  470. X-     clean_exit(EXIT_REJECT);
  471. X-   }
  472. X- 
  473. X-   /* If success, open the dump file */
  474. X-   if ((dumpfd = creat(tmpname, 0666)) < 0) {
  475. X-     fprintf(stderr, "%s: Failed to create dump file %s: %s\n",
  476. X-         progname, tmpname, sys_errlist[errno]);
  477. X-     clean_exit(EXIT_SYSTEM);
  478. X-   }
  479. X-   close(dumpfd);
  480. X-   if ((dumpfd = open(tmpname, O_RDWR)) < 0) {
  481. X-     fprintf(stderr, "%s: Failed to re-open dump file %s: %s\n",
  482. X-         progname, tmpname, sys_errlist[errno]);
  483. X-     clean_exit(EXIT_SYSTEM);
  484. X-   }
  485. X    dumpindex = 0;        /* start at index 0 */
  486. X  
  487. X    if (directory != 0) {
  488. X--- 307,431 ----
  489. X        full = 0;
  490. X      }
  491. X  
  492. X!     if (tapewrite) {
  493. X!       fprintf(stderr, "Doing %s dump of %s volume %s to tape\n",
  494. X!           directory == 0 ? (full ? "full" : "incremental") : "directory",
  495. X!           macname, directory != 0 ? directory : disk);
  496. X!       timenow = time(NULL);
  497. X!       sprintf(tapeheader+1, "Dump of %s on %s", dumpname, ctime(&timenow));
  498. X!       tapeheader[0] = strlen(tapeheader+1);
  499. X!     } else if (!taperead) {
  500. X!       fprintf(stderr, "Doing %s dump to %s\n",
  501. X!           directory == 0 ? (full ? "full" : "incremental") : "directory",
  502. X!           dumpname);
  503. X!     }
  504. X    }
  505. X  
  506. X+   if (taperead) {
  507. X+     readbytes(stdin, tapeheader, strlen(magicheader));
  508. X+     if (strcmp(magicheader, tapeheader) != 0) {
  509. X+       fprintf(stderr, "Bad header: %s\n", tapeheader);
  510. X+       clean_exit(EXIT_USER);
  511. X+     }
  512. X+     readbytes(stdin, tapeheader, 1);
  513. X+     readbytes(stdin, tapeheader+1, tapeheader[0]);
  514. X+     fprintf(stderr, "%s", tapeheader+1);
  515. X+   } else {
  516. X    /* Init appletalk */
  517. X!     abInit(debug);
  518. X!     
  519. X!     /* Look up the macintosh */
  520. X!     nbpInit();
  521. X!     strcpy(&en.objStr, macname);
  522. X!     strcpy(&en.typeStr, "DUMPDEV");
  523. X!     strcpy(&en.zoneStr, zone);
  524. X!     
  525. X!     nbpr.nbpRetransmitInfo.retransInterval = 8;
  526. X!     nbpr.nbpRetransmitInfo.retransCount = 20;
  527. X!     nbpr.nbpBufPtr = nbpt;
  528. X!     nbpr.nbpBufSize = sizeof(nbpt);
  529. X!     nbpr.nbpDataField = 1;
  530. X!     nbpr.nbpEntityPtr = &en;
  531. X!     err = NBPLookup(&nbpr, FALSE);
  532. X!     if (err != noErr || nbpr.nbpDataField <= 0) {
  533. X!       fprintf(stderr, "NBP Lookup of %s failed\n", macname);
  534. X!       clean_exit(EXIT_NOMAC);
  535. X!     }
  536. X!     /* Extract the first item */
  537. X!     NBPExtract(nbpt, nbpr.nbpDataField, 1, &en, &macaddr);
  538. X!     
  539. X!     /* No longer need the NBP socket */
  540. X!     nbpShutdown();
  541. X!     
  542. X      printf("Dump device at %d/%d:%02x\n", htons(macaddr.net), macaddr.node,
  543. X!        macaddr.skt);
  544. X  
  545. X!     if (getdisknames) {
  546. X!       int gotname = 0;
  547. X!       register int i;
  548. X!       struct VolNameRecord *vnp;
  549. X!       
  550. X!       for(i = 1; ; ++i) {
  551. X!     register short *ip = (short *)buffer;
  552. X!     *ip = htons(i);
  553. X!     
  554. X!     if (send_cmd(VOLUME_NAME, buffer, sizeof(short)) != ACK) {
  555. X!       if (!gotname) 
  556. X!         /* convert response to a C string */
  557. X!         fprintf(stderr, "%s: Response: %s\n", progname, PtoCStr(recbuffer));
  558. X!       break;
  559. X!     }
  560. X!     gotname = 1;
  561. X!     vnp = (struct VolNameRecord *)recbuffer;
  562. X!     printf("Volume index %d, disk=\"%s\" %dMB\n", i,
  563. X!            PtoCStr(vnp->volname), htonl(vnp->size)/(1024*1024));
  564. X        }
  565. X!       /* Have seen all volumes */
  566. X!       clean_exit(EXIT_OK);
  567. X      }
  568. X!     
  569. X!   /* Try to access the right disk volume on the mac */
  570. X!     if (directory != 0) {
  571. X!       buffer[0] = strlen(directory);
  572. X!       strcpy(&buffer[1], directory);
  573. X!     } else {
  574. X!       buffer[0] = strlen(disk);
  575. X!       strcpy(&buffer[1], disk);
  576. X!     }
  577. X!     if (send_cmd(directory == 0 ? 
  578. X!          (full ? BEGIN_FULL : BEGIN_INCR) : BEGIN_DIRECTORY,
  579. X!          buffer, buffer[0]+1) != ACK) {
  580. X!       /* convert response to a C string */
  581. X!       fprintf(stderr, "%s: Failed to dump %s. Response: %s\n", progname,
  582. X!           directory == 0 ? disk : directory, PtoCStr(recbuffer));
  583. X!       clean_exit(EXIT_REJECT);
  584. X!     }
  585. X    }
  586. X  
  587. X!   /* If success, open the dump file or get set for stdout */
  588. X! 
  589. X!   if (tapewrite) {
  590. X!     dumpfd = fileno(stdout);
  591. X! #ifdef DOUBLEBUFFER
  592. X!     configure_nowait(dumpfd);
  593. X! #endif
  594. X!     writebytes(dumpfd, magicheader, strlen(magicheader));
  595. X!     writebytes(dumpfd, tapeheader, tapeheader[0]+1);
  596. X    } else {
  597. X!     if (!verify) {
  598. X!       if ((dumpfd = creat(tmpname, 0666)) < 0) {
  599. X!     fprintf(stderr, "%s: Failed to create dump file %s: %s\n",
  600. X!         progname, tmpname, sys_errlist[errno]);
  601. X!     clean_exit(EXIT_SYSTEM);
  602. X!       }
  603. X!       close(dumpfd);
  604. X!       if ((dumpfd = open(tmpname, O_RDWR)) < 0) {
  605. X!     fprintf(stderr, "%s: Failed to re-open dump file %s: %s\n",
  606. X!         progname, tmpname, sys_errlist[errno]);
  607. X!     clean_exit(EXIT_SYSTEM);
  608. X!       }
  609. X!     }
  610. X    }
  611. X    dumpindex = 0;        /* start at index 0 */
  612. X  
  613. X    if (directory != 0) {
  614. X***************
  615. X*** 342,350 ****
  616. X        clean_exit(EXIT_BADREC);
  617. X      }
  618. X      lastrec.nxtdir = htonl(dumpindex); /* set the link field */
  619. X!     lseek(dumpfd, 0L, 0);
  620. X!     write(dumpfd, &lastrec, htonl(lastrec.reclen));
  621. X!     lseek(dumpfd, dumpindex, L_SET);
  622. X    } else {
  623. X      /* Pull over the records to make the dump */
  624. X      next_record();        /* get the volume record */
  625. X--- 456,466 ----
  626. X        clean_exit(EXIT_BADREC);
  627. X      }
  628. X      lastrec.nxtdir = htonl(dumpindex); /* set the link field */
  629. X!     if (!tapewrite && !verify) {
  630. X!       lseek(dumpfd, 0L, 0);
  631. X!       write(dumpfd, &lastrec, htonl(lastrec.reclen));
  632. X!       lseek(dumpfd, dumpindex, L_SET);
  633. X!     }
  634. X    } else {
  635. X      /* Pull over the records to make the dump */
  636. X      next_record();        /* get the volume record */
  637. X***************
  638. X*** 362,381 ****
  639. X        fprintf(stderr, "%s: Dump of %s failed\n", progname, disk);
  640. X        clean_exit(exitcode);
  641. X      }
  642. X  
  643. X!     /* Set the number of files seen into the volume record */
  644. X!     /* (the MAC only keeps track of files on root) */
  645. X!     set_filecount(dumpfd, totalfiles);
  646. X    }
  647. X!   close(dumpfd);
  648. X! 
  649. X!   /* Rename the temp file to the correct name */
  650. X!   unlink(dumpname);
  651. X!   link(tmpname, dumpname);
  652. X!   unlink(tmpname);
  653. X!   /* If full make sure there is no old incr */
  654. X!   if (full) unlink(incrname);
  655. X! 
  656. X    clean_exit(EXIT_OK);
  657. X  }
  658. X  
  659. X--- 478,507 ----
  660. X        fprintf(stderr, "%s: Dump of %s failed\n", progname, disk);
  661. X        clean_exit(exitcode);
  662. X      }
  663. X+     
  664. X+     if (!tapewrite && !verify) {
  665. X+       /* Set the number of files seen into the volume record */
  666. X+       /* (the MAC only keeps track of files on root) */
  667. X+       set_filecount(dumpfd, totalfiles);
  668. X+     }
  669. X  
  670. X!     if (tapewrite) {
  671. X!       flushbuffer();
  672. X! #ifdef DOUBLEBUFFER
  673. X!       wait_for_io();
  674. X! #endif
  675. X!     }
  676. X!     
  677. X!     close(dumpfd);
  678. X!     
  679. X!     /* Rename the temp file to the correct name */
  680. X!     unlink(dumpname);
  681. X!     link(tmpname, dumpname);
  682. X!     unlink(tmpname);
  683. X!     /* If full make sure there is no old incr */
  684. X!     if (full) unlink(incrname);
  685. X    }
  686. X!   
  687. X    clean_exit(EXIT_OK);
  688. X  }
  689. X  
  690. X***************
  691. X*** 402,426 ****
  692. X        ++totalfiles;        /* a directory counts for our purposes */
  693. X        retval = dumpdir(lastrec.DirID);  /* dump this directory recursively */
  694. X  
  695. X!       /* Update the link field in this directory record */
  696. X!       lseek(dumpfd, thisdirrec, L_SET);
  697. X!       if (retval == NAK) return (NAK);
  698. X!       if (read(dumpfd, &lastrec, sizeof(lastrec)) < sizeof(lastrec) - 32) {
  699. X!     fprintf(stderr,
  700. X!         "%s: error re-reading directory record: %s\n",
  701. X!         progname, sys_errlist[errno]);
  702. X!     clean_exit(EXIT_SYSTEM);
  703. X!       } else if ( htonl(lastrec.rectype) != REC_DIR) {
  704. X!     fprintf(stderr,
  705. X!         "%s: error re-reading directory record, got type %d\n",
  706. X!         progname, htonl(lastrec.rectype));
  707. X!     clean_exit(EXIT_SYSTEM);
  708. X        }
  709. X- 
  710. X-       lastrec.nxtdir = htonl(dumpindex); /* set the link field */
  711. X-       lseek(dumpfd, thisdirrec, 0);
  712. X-       write(dumpfd, &lastrec, htonl(lastrec.reclen));
  713. X-       lseek(dumpfd, dumpindex, L_SET);
  714. X      } else if (htonl(lastrec.rectype) == REC_EODIR) {
  715. X        if (lastrec.DirID != thisdirnum) {
  716. X      fprintf(stderr, "%s: wrong directory number in END_OF_DIR record\n",
  717. X--- 528,554 ----
  718. X        ++totalfiles;        /* a directory counts for our purposes */
  719. X        retval = dumpdir(lastrec.DirID);  /* dump this directory recursively */
  720. X  
  721. X!       if (!tapewrite && !verify) {
  722. X!     /* Update the link field in this directory record */
  723. X!     lseek(dumpfd, thisdirrec, L_SET);
  724. X!     if (retval == NAK) return (NAK);
  725. X!     if (read(dumpfd, &lastrec, sizeof(lastrec)) < sizeof(lastrec) - 32) {
  726. X!       fprintf(stderr,
  727. X!           "%s: error re-reading directory record: %s\n",
  728. X!           progname, sys_errlist[errno]);
  729. X!       clean_exit(EXIT_SYSTEM);
  730. X!     } else if ( htonl(lastrec.rectype) != REC_DIR) {
  731. X!       fprintf(stderr,
  732. X!           "%s: error re-reading directory record, got type %d\n",
  733. X!           progname, htonl(lastrec.rectype));
  734. X!       clean_exit(EXIT_SYSTEM);
  735. X!     }
  736. X!     
  737. X!     lastrec.nxtdir = htonl(dumpindex); /* set the link field */
  738. X!     lseek(dumpfd, thisdirrec, 0);
  739. X!     write(dumpfd, &lastrec, htonl(lastrec.reclen));
  740. X!     lseek(dumpfd, dumpindex, L_SET);
  741. X        }
  742. X      } else if (htonl(lastrec.rectype) == REC_EODIR) {
  743. X        if (lastrec.DirID != thisdirnum) {
  744. X      fprintf(stderr, "%s: wrong directory number in END_OF_DIR record\n",
  745. X***************
  746. X*** 487,518 ****
  747. X   */
  748. X  next_record()
  749. X  {
  750. X!   register int i, j;
  751. X!   register int partial;        /* set on partial record received */
  752. X  
  753. X! /* exitcode set in send_cmd when explicit in this routine */
  754. X!   if (send_cmd(NEXT_RECORD, 0, 0) == NAK) {
  755. X!     printf("NAK: %s\n", PtoCStr(recbuffer));
  756. X!     return(NAK);
  757. X    }
  758. X-   if (debug) print_rec(stdout, recbuffer, 1);
  759. X  
  760. X    /* Save first path of the record */
  761. X    bcopy(recbuffer, &lastrec, sizeof(lastrec));
  762. X-   do {
  763. X-     partial = (((u_char *)&recBDS[0].userData)[0] == PARTIAL);
  764. X  
  765. X      for(i = 0; i < recNBDS; ++i) {
  766. X        dumpindex += recBDS[i].dataSize;
  767. X!       j = recBDS[i].dataSize;
  768. X!       if (write(dumpfd, recBDS[i].buffPtr, j) != j) {
  769. X!     exitcode = EXIT_WRITEFAIL;
  770. X!     return(NAK);
  771. X        }
  772. X      }
  773. X!     if (partial && send_cmd(CONTINUE_RECORD, 0, 0) == NAK) return(NAK);
  774. X!   } while(partial);
  775. X! 
  776. X    return(ACK);
  777. X  }
  778. X      
  779. X--- 615,711 ----
  780. X   */
  781. X  next_record()
  782. X  {
  783. X!   register int i, j, k;
  784. X!   char partial, moretocome;        /* set on partial record received */
  785. X!   register char *p;
  786. X  
  787. X!   if (taperead) {
  788. X!     i = readbytes(stdin, &partial, sizeof partial);
  789. X!     if (i != sizeof partial) return (NAK);
  790. X!     if (partial == -1) return NAK;
  791. X!     i = readbytes(stdin, &recNBDS, sizeof recNBDS);
  792. X!     if (i != sizeof recNBDS) return (NAK);
  793. X!     for(i = 0, p = recbuffer; i < atpMaxNum; ++i, p += atpMaxData) {
  794. X!       recBDS[i].buffPtr = p;
  795. X!       recBDS[i].buffSize = atpMaxData;
  796. X!     }
  797. X!     for (j = 0; j < recNBDS; j++) {
  798. X!       i = readbytes(stdin, &recBDS[j].dataSize, sizeof recBDS[j].dataSize);
  799. X!       if (i != sizeof recBDS[j].dataSize) return (NAK);
  800. X!       i = readbytes(stdin, recBDS[j].buffPtr, recBDS[j].dataSize);
  801. X!       if (i != recBDS[j].dataSize) return (NAK);
  802. X!       if (debug > 1) {
  803. X!     fprintf(stderr, "Read block: %d bytes\n", recBDS[j].dataSize);
  804. X!       }
  805. X!     }
  806. X!   } else {
  807. X!     if (send_cmd(NEXT_RECORD, 0, 0) == NAK) {
  808. X!       printf("NAK: %s\n", PtoCStr(recbuffer));
  809. X!       return(NAK);
  810. X!     }
  811. X!     partial = (((u_char *)&recBDS[0].userData)[0] == PARTIAL);
  812. X    }
  813. X  
  814. X+   if (debug) print_rec(stderr, recbuffer, 1);
  815. X+ 
  816. X    /* Save first path of the record */
  817. X    bcopy(recbuffer, &lastrec, sizeof(lastrec));
  818. X  
  819. X+   /* Loop through, writing the data to the disk or tape buffer, and
  820. X+      reading the next segment if the previous read was for a partial
  821. X+      record.
  822. X+   */
  823. X+ 
  824. X+   moretocome = 1;
  825. X+   while (moretocome) {
  826. X+     moretocome = partial;
  827. X+     if (debug > 1) {
  828. X+       fprintf(stderr, "Write record: partial %d, NBDS %d\n", partial, recNBDS);
  829. X+     }
  830. X+     if (tapewrite) {
  831. X+       writebytes(dumpfd, &partial, sizeof partial);
  832. X+       writebytes(dumpfd, &recNBDS, sizeof recNBDS);
  833. X+     }
  834. X      for(i = 0; i < recNBDS; ++i) {
  835. X+       if (tapewrite) {
  836. X+     writebytes(dumpfd, &recBDS[i].dataSize, sizeof recBDS[i].dataSize);
  837. X+     writebytes(dumpfd, recBDS[i].buffPtr, recBDS[i].dataSize);
  838. X+       } else {
  839. X+     write(dumpfd, recBDS[i].buffPtr, recBDS[i].dataSize);
  840. X+       }
  841. X+       if (debug > 1) {
  842. X+     fprintf(stderr, "  Write block: %d bytes at %d\n", recBDS[i].dataSize,
  843. X+         dumpindex);
  844. X+       }
  845. X        dumpindex += recBDS[i].dataSize;
  846. X!     }
  847. X!     if (partial) {
  848. X!       if (taperead) {
  849. X!     i = readbytes(stdin, &partial, sizeof partial);
  850. X!     if (i != sizeof partial) return (NAK);
  851. X!     if (partial == -1) return NAK;
  852. X!     i = readbytes(stdin, &recNBDS, sizeof recNBDS);
  853. X!     if (i != sizeof recNBDS) return (NAK);
  854. X!     for (j = 0; j < recNBDS; j++) {
  855. X!       i = readbytes(stdin, &recBDS[j].dataSize,
  856. X!            sizeof recBDS[j].dataSize);
  857. X!       if (i != sizeof recBDS[j].dataSize) return (NAK);
  858. X!       i = readbytes(stdin, recBDS[j].buffPtr, recBDS[j].dataSize);
  859. X!       if (i != recBDS[j].dataSize) return (NAK);
  860. X!     }
  861. X!       } else {
  862. X!     if (send_cmd(CONTINUE_RECORD, 0, 0) == NAK) {
  863. X!       if (tapewrite) {
  864. X!         partial = -1;
  865. X!         writebytes(dumpfd, &partial, sizeof partial);
  866. X!       }
  867. X!       return(NAK);
  868. X!     }
  869. X!     partial = (((u_char *)&recBDS[0].userData)[0] == PARTIAL);
  870. X        }
  871. X      }
  872. X!   }
  873. X!   
  874. X    return(ACK);
  875. X  }
  876. X      
  877. X***************
  878. X*** 546,556 ****
  879. X   */
  880. X  clean_exit(code)
  881. X  {
  882. X!   if (tmpname[0]) unlink(tmpname);
  883. X    exit(code);
  884. X  }
  885. X  
  886. X  /*
  887. X   * CtoPStr - C String to Pascal string in place.
  888. X   */
  889. X  char *CtoPStr(p)
  890. X--- 739,784 ----
  891. X   */
  892. X  clean_exit(code)
  893. X  {
  894. X!   if (tmpname[0] && !verify) unlink(tmpname);
  895. X    exit(code);
  896. X  }
  897. X  
  898. X  /*
  899. X+  * readbytes - read bytes from a file or socket, guaranteeing that we get
  900. X+  * as many as we ask for unless EOF occurs.  Use the big buffer.
  901. X+  */
  902. X+ 
  903. X+ int readbytes(theFile, buffer, howMany)
  904. X+      FILE *theFile;
  905. X+      char *buffer;
  906. X+      int howMany;
  907. X+ {
  908. X+   int remaining, got, total;
  909. X+   remaining = howMany;
  910. X+   total = 0;
  911. X+   while (remaining > 0) {
  912. X+     if (tapebufferavail == 0) {
  913. X+       tapebufferavail = read(fileno(theFile), tapebuffer, tapebuffersize);
  914. X+       if (tapebufferavail == 0) return total;
  915. X+       if (tapebufferavail < 0) {
  916. X+     perror("Error reading from standard input");
  917. X+     clean_exit(EXIT_SYSTEM);
  918. X+       }
  919. X+       tapebuffercount = 0;
  920. X+     }
  921. X+     got = tapebufferavail;
  922. X+     if (got > remaining) got = remaining;
  923. X+     memcpy(buffer, tapebuffer+tapebuffercount, got);
  924. X+     total += got;
  925. X+     buffer += got;
  926. X+     tapebuffercount += got;
  927. X+     tapebufferavail -= got;
  928. X+     remaining -= got;
  929. X+   }
  930. X+   return total;
  931. X+ }
  932. X+ 
  933. X+ /*
  934. X   * CtoPStr - C String to Pascal string in place.
  935. X   */
  936. X  char *CtoPStr(p)
  937. X***************
  938. X*** 579,582 ****
  939. X--- 807,960 ----
  940. X    *p0++ = 0;
  941. X  
  942. X    return(p);
  943. X+ }
  944. X+ 
  945. X+ void initbuffer()
  946. X+ {
  947. X+   int flags;
  948. X+   tapebuffer = malloc(tapebuffersize);
  949. X+   if (!tapebuffer) {
  950. X+     fprintf(stderr, "Could not allocate tape buffer\n");
  951. X+     clean_exit(EXIT_SYSTEM);
  952. X+   }
  953. X+   tapebuffercount = 0;
  954. X+   tapebufferavail = 0;
  955. X+ #ifdef DOUBLEBUFFER
  956. X+   writebuffer = malloc(tapebuffersize);
  957. X+   if (!writebuffer) {
  958. X+     fprintf(stderr, "Could not allocate tape buffer\n");
  959. X+     clean_exit(EXIT_SYSTEM);
  960. X+   }
  961. X+   write_in_progress = 0;
  962. X+   write_offset = 0;
  963. X+   write_completed = 0;
  964. X+ #endif
  965. X+   return;
  966. X+ }
  967. X+ 
  968. X+ 
  969. X+ #ifdef DOUBLEBUFFER
  970. X+ 
  971. X+ int configure_nowait(fd)
  972. X+      int fd;
  973. X+ {
  974. X+   int flags;
  975. X+   flags = fcntl(fd, F_GETFL, 0);
  976. X+   if (fcntl(fd, F_SETFL, flags | FNDELAY) == -1) {
  977. X+     return 0;
  978. X+   }
  979. X+   flags = fcntl(fd, F_GETFL, 0);
  980. X+   if (!(flags & FNDELAY)) {
  981. X+     fprintf("Failed to set FNDELAY flag!\n");
  982. X+     return;
  983. X+   }
  984. X+   fprintf(stderr, "Successfully configured for asynchronous writes\n");
  985. X+ }
  986. X+ 
  987. X+ /*
  988. X+   pushbytes() returns -1 if a "can't write, would block" condition
  989. X+   exists when it tries to write, and >= 0 otherwise.
  990. X+ */
  991. X+ 
  992. X+ int pushbytes(fd)
  993. X+ {
  994. X+   int result, push;
  995. X+   if (!write_in_progress) {
  996. X+     return 0;
  997. X+   }
  998. X+   push = tapebuffersize-write_offset;
  999. X+   if (write_trace) {
  1000. X+     fprintf(stderr, "Writing %d bytes... ", push);
  1001. X+     fflush(stderr);
  1002. X+   }
  1003. X+   result = write(fd, writebuffer+write_offset, push);
  1004. X+   if (result < 0) {
  1005. X+     if (errno != EWOULDBLOCK) {
  1006. X+       perror("Write error");
  1007. X+       clean_exit(EXIT_SYSTEM);
  1008. X+     }
  1009. X+     if (write_trace) {
  1010. X+       fprintf(stderr, "blocked.\n");
  1011. X+       fflush(stderr);
  1012. X+     }
  1013. X+   } else {
  1014. X+     if (write_trace) {
  1015. X+       fprintf(stderr, "wrote %d\n", result);
  1016. X+       fflush(stderr);
  1017. X+     }
  1018. X+     write_offset += result;
  1019. X+     if (write_offset >= tapebuffersize) {
  1020. X+       write_in_progress = 0;
  1021. X+     }
  1022. X+   }
  1023. X+   return result;
  1024. X+ }
  1025. X+ 
  1026. X+ void wait_for_io(fd)
  1027. X+      int fd;
  1028. X+ {
  1029. X+   int status;
  1030. X+   while (write_in_progress) {
  1031. X+     status = pushbytes(fd);
  1032. X+     if (status == -1) {
  1033. X+       if (write_trace) {
  1034. X+     fprintf(stderr, "Issuing wait\n");
  1035. X+     fflush(stderr);
  1036. X+       }
  1037. X+       sleep(1);
  1038. X+     }
  1039. X+   }
  1040. X+ }
  1041. X+ 
  1042. X+ #endif
  1043. X+ 
  1044. X+ void flushbuffer(fd)
  1045. X+      int fd;
  1046. X+ {
  1047. X+   int result;
  1048. X+   if (tapebuffercount > 0) {
  1049. X+     if (tapebuffercount < tapebuffersize) {
  1050. X+       memset(tapebuffer+tapebuffercount, 0, tapebuffersize - tapebuffercount);
  1051. X+     }
  1052. X+ #ifdef DOUBLEBUFFER
  1053. X+     wait_for_io(fd);
  1054. X+     memcpy(writebuffer, tapebuffer, tapebuffersize);
  1055. X+     write_offset = 0;
  1056. X+     write_in_progress = 1;
  1057. X+     pushbytes(fd);
  1058. X+ #else
  1059. X+     if (write(fd, tapebuffer, tapebuffersize) == -1) {
  1060. X+       perror("write() failure");
  1061. X+       clean_exit(EXIT_SYSTEM);
  1062. X+     }
  1063. X+ #endif
  1064. X+     tapebuffercount = 0;
  1065. X+   }
  1066. X+ }
  1067. X+ 
  1068. X+ int writebytes(fd, data, count)
  1069. X+      int fd;
  1070. X+      char *data;
  1071. X+      int count;
  1072. X+ {
  1073. X+   int now;
  1074. X+ #ifdef DOUBLEBUFFER
  1075. X+   if (write_in_progress) {
  1076. X+     (void) pushbytes(fd);
  1077. X+   }
  1078. X+ #endif
  1079. X+   while (count > 0) {
  1080. X+     if (tapebuffercount == tapebuffersize) {
  1081. X+       flushbuffer(fd);
  1082. X+     }
  1083. X+     now = tapebuffersize - tapebuffercount;
  1084. X+     if (now > count) {
  1085. X+       now = count;
  1086. X+     }
  1087. X+     memcpy(tapebuffer + tapebuffercount, data, now);
  1088. X+     data += now;
  1089. X+     count -= now;
  1090. X+     tapebuffercount += now;
  1091. X+   }
  1092. X+   return 0;
  1093. X  }
  1094. END_OF_FILE
  1095. if test 25771 -ne `wc -c <'macdump.c.diff'`; then
  1096.     echo shar: \"'macdump.c.diff'\" unpacked with wrong size!
  1097. fi
  1098. # end of 'macdump.c.diff'
  1099. fi
  1100. echo shar: End of shell archive.
  1101. exit 0
  1102.  
  1103.   ==============================================================
  1104. # This is a shell archive.  Save it in a file, remove anything before
  1105. # this line, and then unpack it by entering "sh file".  Note, it may
  1106. # create directories; files and directories will be owned by you and
  1107. # have default permissions.
  1108. #
  1109. # This archive contains:
  1110. #
  1111. #    macdump.man.diff
  1112. #
  1113. echo x - macdump.man.diff
  1114. sed 's/^X//' >macdump.man.diff << 'END-of-macdump.man.diff'
  1115. X*** macdump-merge/macdump.8    Tue Jan 10 11:52:18 1989
  1116. X--- macdump-bbn/macdump.8    Tue Dec 29 14:54:08 1992
  1117. X***************
  1118. X*** 3,14 ****
  1119. X  macdump - perform an automated backup of a Macintosh
  1120. X  .SH SYNTAX
  1121. X  .B macdump
  1122. X! \-user=name \-disk=name [ \-mac=name ] [ \-zone=name ] [ \-full ] [ \-incr ] [ \-debug ] [ \-disknames ]
  1123. X  .SH DESCRIPTION
  1124. X  .I macdump
  1125. X  is run to perform a backup operation of a Macintosh on Appletalk.
  1126. X  The Macintosh must be running the network dump server.
  1127. X  .PP
  1128. X  The 
  1129. X  .B \-user=
  1130. X  parameter specifies the user name that the dump files will be owned by.
  1131. X--- 3,24 ----
  1132. X  macdump - perform an automated backup of a Macintosh
  1133. X  .SH SYNTAX
  1134. X  .B macdump
  1135. X! \-user=name \-disk=name [ \-mac=name ] [ \-zone=name ] [ \-full ] [ \-incr ] [ \-debug ] [ \-disknames ] [ \-tape ] [ \-read ] [ \-blocks=n ] [ \-verify ] [ \-writetrace ]
  1136. X  .SH DESCRIPTION
  1137. X  .I macdump
  1138. X  is run to perform a backup operation of a Macintosh on Appletalk.
  1139. X  The Macintosh must be running the network dump server.
  1140. X+ If the
  1141. X+ .B \-tape
  1142. X+ option is specified, the dump image is written to the standard output
  1143. X+ (which may be redirected to a tape device);
  1144. X+ otherwise the image will be written to a dumpfile.
  1145. X  .PP
  1146. X+ There is not, currently, any way to do a "selective" restore from the
  1147. X+ tape dump to Unix disk \(em you must read back the whole tape, create a
  1148. X+ \fImacrestore\fP\^-compatible full-dump file, and then restore portions of it to
  1149. X+ the Mac over the network by using Restore.
  1150. X+ .PP
  1151. X  The 
  1152. X  .B \-user=
  1153. X  parameter specifies the user name that the dump files will be owned by.
  1154. X***************
  1155. X*** 45,50 ****
  1156. X--- 55,159 ----
  1157. X  options when using the
  1158. X  .B \-diskname
  1159. X  option.
  1160. X+ .PP
  1161. X+ The
  1162. X+ .B \-tape
  1163. X+ option instructs
  1164. X+ .I macdump
  1165. X+ to write the dump image to the standard output;
  1166. X+ if the command line redirects this to a tape device, the dump image will
  1167. X+ be written directly to tape instead of to a disk file.
  1168. X+ .PP
  1169. X+ The
  1170. X+ .B \-read
  1171. X+ option instructs
  1172. X+ .I macdump
  1173. X+ to read from the standard input, which is typically redirected to a tape device,
  1174. X+ and create a dump file that is compatible with the
  1175. X+ .I macrestore
  1176. X+ program.
  1177. X+ If both the
  1178. X+ .B \-tape
  1179. X+ and
  1180. X+ .B \-read
  1181. X+ options are present, the program exits with an error indication.
  1182. X+ .PP
  1183. X+ .B \-verify
  1184. X+ presumes the
  1185. X+ .B \-read
  1186. X+ option, but no dump file is written;
  1187. X+ when an execution of
  1188. X+ .I macdump
  1189. X+ .B \-tape
  1190. X+ is followed by
  1191. X+ .I macdump
  1192. X+ .B \-verify
  1193. X+ the program verifies that all data on the tape is readable.
  1194. X+ It
  1195. X+ .I "does not"
  1196. X+ verify the data on the tape against the data on the Macintosh.
  1197. X+ .PP
  1198. X+ .B \-blocks=
  1199. X+ specifies the number of 512-byte blocks to read or write when using tape;
  1200. X+ the default is 10 blocks.
  1201. X+ Specifying less than 1 block or more than 9999 blocks will cause
  1202. X+ .I macdump
  1203. X+ to exit with an error indication.
  1204. X+ .PP
  1205. X+ The
  1206. X+ .B \-writetrace
  1207. X+ option provides additional debugging for tape operation.
  1208. X+ .SH EXAMPLES
  1209. X+ .PP
  1210. X+ Execute
  1211. X+ .I macdump
  1212. X+ with these options to dump the disk
  1213. X+ .B "Macintosh HD"
  1214. X+ on a Macintosh named
  1215. X+ .I Joe
  1216. X+ to a disk file in the home directory of user
  1217. X+ .I oper.
  1218. X+ .IP
  1219. X+ .B
  1220. X+ macdump -user=oper -disk="Macintosh HD" -mac=Joe -full
  1221. X+ .PP
  1222. X+ The same disk can be dumped to tape in either of two ways:
  1223. X+ direct to the device, or via a pipe to
  1224. X+ .I dd.
  1225. X+ The latter method a bit more complex but
  1226. X+ may give better performance, as it allows
  1227. X+ .I dd
  1228. X+ to be writing one block
  1229. X+ to tape while
  1230. X+ .I macdump
  1231. X+ is filling another block over the network.
  1232. X+ To use the QIC-150 tapedrive
  1233. X+ .I rst0,
  1234. X+ .IP
  1235. X+ .B
  1236. X+ macdump -disk="Macintosh HD" -mac=Joe -full -tape -blocks=20 > /dev/rst0
  1237. X+ .PP
  1238. X+ or
  1239. X+ .IP
  1240. X+ .B
  1241. X+ macdump -disk="Macintosh HD" -mac=Joe -full -tape -blocks=20 | \\
  1242. X+ .IP
  1243. X+ .B
  1244. X+ dd ibs=20b obs=200b of=/dev/rst0
  1245. X+ .PP
  1246. X+ To verify that dump
  1247. X+ .IP
  1248. X+ .B
  1249. X+ macdump -disk="Macintosh HD" -mac=Joe -verify -blocks=20 < /dev/rst0
  1250. X+ .PP
  1251. X+ To create a disk dump file for use by
  1252. X+ .I macrestore,
  1253. X+ .IP
  1254. X+ .B
  1255. X+ dd if=/dev/rst0 ibs=200b obs=20b | macdump -disk="Macintosh HD" -mac=Joe -read
  1256. X+ .PP
  1257. X+ Note the use of double quotes to preserve the spaces in the hard disk
  1258. X+ volume name in these examples.
  1259. X  .SH SEE ALSO
  1260. X  macrestore(8), macdumpdir(8)
  1261. X  
  1262. END-of-macdump.man.diff
  1263. exit
  1264.  
  1265.