Browse Source

Plan 9 from Bell Labs 2007-01-18

David du Colombier 17 years ago
parent
commit
727c210262
9 changed files with 543 additions and 237 deletions
  1. 7 7
      dist/replica/_plan9.db
  2. 7 7
      dist/replica/plan9.db
  3. 8 0
      dist/replica/plan9.log
  4. 1 1
      sys/man/1/rc
  5. 5 0
      sys/man/1/tar
  6. 4 1
      sys/man/4/snap
  7. 18 11
      sys/man/8/ping
  8. 308 116
      sys/src/cmd/ip/ping.c
  9. 185 94
      sys/src/cmd/tar.c

+ 7 - 7
dist/replica/_plan9.db

@@ -456,7 +456,7 @@
 386/bin/upas/fs - 775 sys sys 1143863649 334451
 386/bin/upas/isspam - 775 sys sys 1064598349 38
 386/bin/upas/list - 775 sys sys 1135101638 82799
-386/bin/upas/marshal - 775 sys sys 1143863649 134381
+386/bin/upas/marshal - 775 sys sys 1169065328 134608
 386/bin/upas/ml - 775 sys sys 1132506879 123917
 386/bin/upas/mlmgr - 775 sys sys 1132506880 104539
 386/bin/upas/mlowner - 775 sys sys 1130594799 92131
@@ -7368,7 +7368,7 @@ sys/man/1/proof - 664 sys sys 1113743329 2300
 sys/man/1/ps - 664 sys sys 1144686669 1722
 sys/man/1/ps2pdf - 664 sys sys 1032632098 1359
 sys/man/1/pwd - 664 sys sys 1104639653 744
-sys/man/1/rc - 664 sys sys 1144685483 20019
+sys/man/1/rc - 664 sys sys 1169092054 20021
 sys/man/1/replica - 664 sys sys 1138843328 7210
 sys/man/1/resample - 664 sys sys 1015024740 1083
 sys/man/1/rio - 664 sys sys 1155362586 14707
@@ -7392,7 +7392,7 @@ sys/man/1/strip - 664 sys sys 1131293239 523
 sys/man/1/sum - 664 sys sys 984772442 1390
 sys/man/1/syscall - 664 sys sys 1016466457 1439
 sys/man/1/tail - 664 sys sys 1113743327 1413
-sys/man/1/tar - 664 sys sys 1165622307 3439
+sys/man/1/tar - 664 sys sys 1169092135 3577
 sys/man/1/tbl - 664 sys sys 944959674 4308
 sys/man/1/tcs - 664 sys sys 1143131200 2654
 sys/man/1/tee - 664 sys sys 969499886 351
@@ -7636,7 +7636,7 @@ sys/man/4/ratfs - 664 sys sys 1157898800 3276
 sys/man/4/rdbfs - 664 sys sys 944959699 1123
 sys/man/4/rio - 664 sys sys 1023206844 8660
 sys/man/4/sacfs - 664 sys sys 964886843 907
-sys/man/4/snap - 664 sys sys 1017251244 1833
+sys/man/4/snap - 664 sys sys 1169092032 1908
 sys/man/4/srv - 664 sys sys 1162907929 4685
 sys/man/4/tapefs - 664 sys sys 1140965924 1861
 sys/man/4/telco - 664 sys sys 1015024814 4359
@@ -7745,7 +7745,7 @@ sys/man/8/newuser - 664 sys sys 1116954242 2418
 sys/man/8/nfsserver - 664 sys sys 1163208425 3587
 sys/man/8/pcmcia - 664 sys sys 944959679 408
 sys/man/8/pem - 664 sys sys 1060263669 1189
-sys/man/8/ping - 664 sys sys 1139667147 3489
+sys/man/8/ping - 664 sys sys 1169091081 3639
 sys/man/8/plan9.ini - 664 sys sys 1167276434 22689
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
 sys/man/8/ppp - 664 sys sys 1125530075 4414
@@ -12387,7 +12387,7 @@ sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1168894057 2587
 sys/src/cmd/ip/ipconfig.c - 664 sys sys 1166761782 35168
 sys/src/cmd/ip/measure.c - 664 sys sys 944961011 3733
 sys/src/cmd/ip/mkfile - 664 sys sys 1131110598 1243
-sys/src/cmd/ip/ping.c - 664 sys sys 1166760556 5721
+sys/src/cmd/ip/ping.c - 664 sys sys 1169091087 8437
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353
 sys/src/cmd/ip/ppp/compress.c - 664 sys sys 1072729513 11774
@@ -13352,7 +13352,7 @@ sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1166887348 4096
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1140814625 3993
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1140814625 6588
-sys/src/cmd/tar.c - 664 sys sys 1155348700 24133
+sys/src/cmd/tar.c - 664 sys sys 1169092124 25725
 sys/src/cmd/tbl - 20000000775 sys sys 1039727580 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987

+ 7 - 7
dist/replica/plan9.db

@@ -456,7 +456,7 @@
 386/bin/upas/fs - 775 sys sys 1143863649 334451
 386/bin/upas/isspam - 775 sys sys 1064598349 38
 386/bin/upas/list - 775 sys sys 1135101638 82799
-386/bin/upas/marshal - 775 sys sys 1143863649 134381
+386/bin/upas/marshal - 775 sys sys 1169065328 134608
 386/bin/upas/ml - 775 sys sys 1132506879 123917
 386/bin/upas/mlmgr - 775 sys sys 1132506880 104539
 386/bin/upas/mlowner - 775 sys sys 1130594799 92131
@@ -7368,7 +7368,7 @@ sys/man/1/proof - 664 sys sys 1113743329 2300
 sys/man/1/ps - 664 sys sys 1144686669 1722
 sys/man/1/ps2pdf - 664 sys sys 1032632098 1359
 sys/man/1/pwd - 664 sys sys 1104639653 744
-sys/man/1/rc - 664 sys sys 1144685483 20019
+sys/man/1/rc - 664 sys sys 1169092054 20021
 sys/man/1/replica - 664 sys sys 1138843328 7210
 sys/man/1/resample - 664 sys sys 1015024740 1083
 sys/man/1/rio - 664 sys sys 1155362586 14707
@@ -7392,7 +7392,7 @@ sys/man/1/strip - 664 sys sys 1131293239 523
 sys/man/1/sum - 664 sys sys 984772442 1390
 sys/man/1/syscall - 664 sys sys 1016466457 1439
 sys/man/1/tail - 664 sys sys 1113743327 1413
-sys/man/1/tar - 664 sys sys 1165622307 3439
+sys/man/1/tar - 664 sys sys 1169092135 3577
 sys/man/1/tbl - 664 sys sys 944959674 4308
 sys/man/1/tcs - 664 sys sys 1143131200 2654
 sys/man/1/tee - 664 sys sys 969499886 351
@@ -7636,7 +7636,7 @@ sys/man/4/ratfs - 664 sys sys 1157898800 3276
 sys/man/4/rdbfs - 664 sys sys 944959699 1123
 sys/man/4/rio - 664 sys sys 1023206844 8660
 sys/man/4/sacfs - 664 sys sys 964886843 907
-sys/man/4/snap - 664 sys sys 1017251244 1833
+sys/man/4/snap - 664 sys sys 1169092032 1908
 sys/man/4/srv - 664 sys sys 1162907929 4685
 sys/man/4/tapefs - 664 sys sys 1140965924 1861
 sys/man/4/telco - 664 sys sys 1015024814 4359
@@ -7745,7 +7745,7 @@ sys/man/8/newuser - 664 sys sys 1116954242 2418
 sys/man/8/nfsserver - 664 sys sys 1163208425 3587
 sys/man/8/pcmcia - 664 sys sys 944959679 408
 sys/man/8/pem - 664 sys sys 1060263669 1189
-sys/man/8/ping - 664 sys sys 1139667147 3489
+sys/man/8/ping - 664 sys sys 1169091081 3639
 sys/man/8/plan9.ini - 664 sys sys 1167276434 22689
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
 sys/man/8/ppp - 664 sys sys 1125530075 4414
@@ -12387,7 +12387,7 @@ sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1168894057 2587
 sys/src/cmd/ip/ipconfig.c - 664 sys sys 1166761782 35168
 sys/src/cmd/ip/measure.c - 664 sys sys 944961011 3733
 sys/src/cmd/ip/mkfile - 664 sys sys 1131110598 1243
-sys/src/cmd/ip/ping.c - 664 sys sys 1166760556 5721
+sys/src/cmd/ip/ping.c - 664 sys sys 1169091087 8437
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353
 sys/src/cmd/ip/ppp/compress.c - 664 sys sys 1072729513 11774
@@ -13352,7 +13352,7 @@ sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1166887348 4096
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1140814625 3993
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1140814625 6588
-sys/src/cmd/tar.c - 664 sys sys 1155348700 24133
+sys/src/cmd/tar.c - 664 sys sys 1169092124 25725
 sys/src/cmd/tbl - 20000000775 sys sys 1039727580 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987

+ 8 - 0
dist/replica/plan9.log

@@ -47366,3 +47366,11 @@
 1168921806 0 c 386/bin/ip/imap4d - 775 sys sys 1168920102 238175
 1168984807 0 c sys/src/cmd/ip/imap4d/mbox.c - 664 sys sys 1168984478 16991
 1169006406 0 c 386/bin/ip/imap4d - 775 sys sys 1169006128 238175
+1169037005 0 c 386/bin/upas/marshal - 775 sys sys 1169035586 134608
+1169065806 0 c 386/bin/upas/marshal - 775 sys sys 1169065328 134608
+1169091006 0 c sys/man/8/ping - 664 sys sys 1169091081 3639
+1169091006 1 c sys/src/cmd/ip/ping.c - 664 sys sys 1169091087 8437
+1169092806 0 c sys/man/1/tar - 664 sys sys 1169092135 3577
+1169092806 1 c sys/man/1/rc - 664 sys sys 1169092054 20021
+1169092806 2 c sys/man/4/snap - 664 sys sys 1169092032 1908
+1169092806 3 c sys/src/cmd/tar.c - 664 sys sys 1169092124 25725

+ 1 - 1
sys/man/1/rc

@@ -983,6 +983,6 @@ to check the value of
 changes
 .BR $status .
 .PP
-Functions that use here documents don't work.
+Functions containing here documents don't work.
 .PP
 Free carets don't get inserted next to keywords.

+ 5 - 0
sys/man/1/tar

@@ -63,6 +63,11 @@ and
 Use the next (numeric) argument as the group id for files in
 the output archive.
 .TP
+.B i
+Ignore errors encountered when reading.
+Errors writing either produce a corrupt archive
+or indicate deeper file system problems.
+.TP
 .B k
 (keep)
 Modifies the behavior of

+ 4 - 1
sys/man/4/snap

@@ -38,7 +38,7 @@ of the named processes to
 .I file 
 (default standard output).
 If 
-.I proc
+.I pid
 is a text string
 rather than a process id,
 .I snap
@@ -101,3 +101,6 @@ The snapshots take up about as much disk space
 as the processes they contain did memory.
 Compressing them when not in use is recommended,
 as is storing them on a rewritable disk.
+.PP
+.I Pid
+as a non-numeric string is unimplemented; it has to be a number.

+ 18 - 11
sys/man/8/ping

@@ -4,18 +4,16 @@ ping, gping, traceroute, hogports \- probe the Internet
 .SH SYNOPSIS
 .B ping
 [
-.B -aflq
+.B -6aflqr
 ] [
 .B -i
 .I interval
 ] [
-.B -r
+.B -n
+.I count
 ] [
 .B -s
 .I size
-] [
-.B -n
-.I count
 ]
 .I destination
 .PP
@@ -71,6 +69,11 @@ returns successfully. Otherwise it returns an error status of
 .PP
 The options are:
 .TP
+.B 6
+use IPv6's ICMP,
+.BR icmpv6 ,
+instead of IPv4's ICMP.
+.TP
 .B a
 adds the IP source and destination addresses to each report.
 .TP
@@ -83,10 +86,6 @@ to be
 .I interval
 milliseconds, default 1000 ms.
 .TP
-.B r
-randomizes the delay with a minimum extra delay of 0 ms and a
-maximum extra delay of the selected interval.
-.TP
 .B l
 causes only lost messages to be reported.
 .TP
@@ -98,13 +97,16 @@ messages be sent, default 32.
 .B q
 suppresses any output (i.e. be quiet).
 .TP
+.B r
+randomizes the delay with a minimum extra delay of 0 ms and a
+maximum extra delay of the selected interval.
+.TP
 .B s
 sets the length of the message to be
 .I size
 bytes, ICMP header included.
 The size cannot be smaller than 32 or
-larger than 8192.  The default is
-64.
+larger than 8192.  The default is 64.
 .PP
 .I Gping
 is a
@@ -189,3 +191,8 @@ the network mounted at
 .B /sys/src/cmd/ip/traceroute.c
 .br
 .B /sys/src/cmd/ip/hogports.c
+.SH SEE ALSO
+.IR ip (3)
+.SH BUGS
+.I Ping
+should be able to adapt automatically to IP v4 or v6.

+ 308 - 116
sys/src/cmd/ip/ping.c

@@ -1,7 +1,31 @@
+/* ping for ip v4 and v6 */
 #include <u.h>
 #include <libc.h>
 #include <ip.h>
 
+enum
+{
+	/* Packet Types */
+	EchoReply	= 0,
+	Unreachable	= 3,
+	SrcQuench	= 4,
+	EchoRequest	= 8,
+	TimeExceed	= 11,
+	Timestamp	= 13,
+	TimestampReply	= 14,
+	InfoRequest	= 15,
+	InfoReply	= 16,
+
+	EchoReplyV6	= 129,
+	EchoRequestV6	= 128,
+
+	MAXMSG		= 32,
+	SLEEPMS		= 1000,
+
+	SECOND		= 1000000000LL,
+	MINUTE		= 60*SECOND,
+};
+
 typedef struct Icmp Icmp;
 struct Icmp
 {
@@ -23,37 +47,51 @@ struct Icmp
 	uchar	data[1];
 };
 
-enum
-{			/* Packet Types */
-	EchoReply	= 0,
-	Unreachable	= 3,
-	SrcQuench	= 4,
-	EchoRequest	= 8,
-	TimeExceed	= 11,
-	Timestamp	= 13,
-	TimestampReply	= 14,
-	InfoRequest	= 15,
-	InfoReply	= 16,
-
-	ICMP_IPSIZE	= 20,
-	ICMP_HDRSIZE	= 8,
-
-	MAXMSG		= 32,
-	SLEEPMS		= 1000,
+typedef struct Icmp6 Icmp6;
+struct Icmp6
+{
+	uchar	vcf[4];
+	uchar	ploadlen[2];
+	uchar	proto;
+	uchar	ttl;
+	uchar	src[16];		/* Ip source */
+	uchar	dst[16];		/* Ip destination */
+	uchar	type;
+	uchar	code;
+	uchar	cksum[2];
+	uchar	icmpid[2];
+	uchar	seq[2];
+	uchar	data[1];
 };
 
 typedef struct Req Req;
 struct Req
 {
-	ushort	seq;	// sequence number
-	vlong	time;	// time sent
+	ushort	seq;	/* sequence number */
+	vlong	time;	/* time sent */
 	vlong	rtt;
 	int	ttl;
 	int	replied;
 	Req	 *next;
 };
-Req	*first;		// request list
-Req	*last;		// ...
+
+typedef struct {
+	char	*net;
+	int	echoreply;
+	unsigned icmphdrsz;
+	int	(*getttl)(void *v);
+	int	(*getseq)(void *v);
+	void	(*putseq)(void *v, ushort seq);
+	int	(*gettype)(void *v);
+	void	(*settype)(void *v);
+	int	(*getcode)(void *v);
+	void	(*setcode)(void *v);
+	void	(*prreply)(Req *r, void *v);
+	void	(*prlost)(ushort seq, void *v);
+} Proto;
+
+Req	*first;		/* request list */
+Req	*last;		/* ... */
 Lock	listlock;
 
 char *argv0;
@@ -69,12 +107,17 @@ ushort firstseq;
 int addresses;
 int flood;
 
-void usage(void);
-void lost(Req*, Icmp*);
-void reply(Req*, Icmp*);
+void lost(Req*, void*);
+void reply(Req*, void*);
 
-#define SECOND 1000000000LL
-#define MINUTE (60LL*SECOND)
+static void
+usage(void)
+{
+	fprint(2,
+	    "usage: %s [-6alq] [-s msgsize] [-i millisecs] [-n #pings] dest\n",
+		argv0);
+	exits("usage");
+}
 
 static void
 catch(void *a, char *msg)
@@ -88,8 +131,163 @@ catch(void *a, char *msg)
 		noted(NDFLT);
 }
 
+
+static int
+getttl4(void *v)
+{
+	return ((Icmp *)v)->ttl;
+}
+
+static int
+getttl6(void *v)
+{
+	return ((Icmp6 *)v)->ttl;
+}
+
+static int
+getseq4(void *v)
+{
+	return nhgets(((Icmp *)v)->seq);
+}
+
+static int
+getseq6(void *v)
+{
+	Icmp6 *ip6 = v;
+
+	return ip6->seq[1]<<8 | ip6->seq[0];
+}
+
+static void
+putseq4(void *v, ushort seq)
+{
+	hnputs(((Icmp *)v)->seq, seq);
+}
+
+static void
+putseq6(void *v, ushort seq)
+{
+	((Icmp6 *)v)->seq[0] = seq;
+	((Icmp6 *)v)->seq[1] = seq>>8;
+}
+
+static int
+gettype4(void *v)
+{
+	return ((Icmp *)v)->type;
+}
+
+static int
+gettype6(void *v)
+{
+	return ((Icmp6 *)v)->type;
+}
+
+static void
+settype4(void *v)
+{
+	((Icmp *)v)->type = EchoRequest;
+}
+
+static void
+settype6(void *v)
+{
+	((Icmp6 *)v)->type = EchoRequestV6;
+}
+
+static int
+getcode4(void *v)
+{
+	return ((Icmp *)v)->code;
+}
+
+static int
+getcode6(void *v)
+{
+	return ((Icmp6 *)v)->code;
+}
+
+static void
+setcode4(void *v)
+{
+	((Icmp *)v)->code = 0;
+}
+
+static void
+setcode6(void *v)
+{
+	((Icmp6 *)v)->code = 0;
+}
+
+static void
+prlost4(ushort seq, void *v)
+{
+	Icmp *ip4 = v;
+
+	print("lost %ud: %V->%V\n", seq, ip4->src, ip4->dst);
+}
+
+static void
+prlost6(ushort seq, void *v)
+{
+	Icmp6 *ip6 = v;
+
+	print("lost %ud: %I->%I\n", seq, ip6->src, ip6->dst);
+}
+
+static void
+prreply4(Req *r, void *v)
+{
+	Icmp *ip4 = v;
+
+	print("%ud: %V->%V rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
+		r->seq - firstseq, ip4->src, ip4->dst, r->rtt, sum/rcvdmsgs,
+		r->ttl);
+}
+
+static void
+prreply6(Req *r, void *v)
+{
+	Icmp *ip6 = v;
+
+	print("%ud: %I->%I rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
+		r->seq - firstseq, ip6->src, ip6->dst, r->rtt, sum/rcvdmsgs,
+		r->ttl);
+}
+
+static Proto v4pr = {
+	"icmp",
+	EchoReply,
+	sizeof(Icmp),
+	getttl4,
+	getseq4,
+	putseq4,
+	gettype4,
+	settype4,
+	getcode4,
+	setcode4,
+	prreply4,
+	prlost4,
+};
+static Proto v6pr = {
+	"icmpv6",
+	EchoReplyV6,
+	sizeof(Icmp6),
+	getttl6,
+	getseq6,
+	putseq6,
+	gettype6,
+	settype6,
+	getcode6,
+	setcode6,
+	prreply6,
+	prlost6,
+};
+
+static Proto *proto = &v4pr;
+
 void
-clean(ushort seq, vlong now, Icmp *ip)
+clean(ushort seq, vlong now, void *v)
 {
 	Req **l, *r;
 
@@ -98,23 +296,23 @@ clean(ushort seq, vlong now, Icmp *ip)
 	for(l = &first; *l; ){
 		r = *l;
 
-		if(ip && r->seq == seq){
+		if(v && r->seq == seq){
 			r->rtt = now-r->time;
-			r->ttl = ip->ttl;
-			reply(r, ip);
+			r->ttl = (*proto->getttl)(v);
+			reply(r, v);
 		}
 
 		if(now-r->time > MINUTE){
 			*l = r->next;
 			r->rtt = now-r->time;
-			if(ip)
-				r->ttl = ip->ttl;
+			if(v)
+				r->ttl = (*proto->getttl)(v);
 			if(r->replied == 0)
-				lost(r, ip);
+				lost(r, v);
 			free(r);
 		}else{
 			last = r;
-			l = &(r->next);
+			l = &r->next;
 		}
 	}
 	unlock(&listlock);
@@ -123,21 +321,18 @@ clean(ushort seq, vlong now, Icmp *ip)
 void
 sender(int fd, int msglen, int interval, int n)
 {
-	char buf[64*1024+512];
-	Icmp *ip;
 	int i, extra;
-	Req *r;
 	ushort seq;
-
-	ip = (Icmp*)buf;
+	char buf[64*1024+512];
+	Req *r;
 
 	srand(time(0));
 	firstseq = seq = rand();
 
-	for(i = 32; i < msglen; i++)
+	for(i = proto->icmphdrsz; i < msglen; i++)
 		buf[i] = i;
-	ip->type = EchoRequest;
-	ip->code = 0;
+	(*proto->settype)(buf);
+	(*proto->setcode)(buf);
 
 	for(i = 0; i < n; i++){
 		if(i != 0){
@@ -145,26 +340,26 @@ sender(int fd, int msglen, int interval, int n)
 			sleep(interval + extra);
 		}
 		r = malloc(sizeof *r);
-		if(r != nil){
-			hnputs(ip->seq, seq);
-			r->seq = seq;
-			r->next = nil;
-			r->replied = 0;
-			r->time = nsec();	/* avoid early free in reply! */
-			lock(&listlock);
-			if(first == nil)
-				first = r;
-			else
-				last->next = r;
-			last = r;
-			unlock(&listlock);
-			r->time = nsec();
-			if(write(fd, ip, msglen) < msglen){
-				fprint(2, "%s: write failed: %r\n", argv0);
-				return;
-			}
-			seq++;
+		if (r == nil)
+			continue;
+		(*proto->putseq)(buf, seq);
+		r->seq = seq;
+		r->next = nil;
+		r->replied = 0;
+		r->time = nsec();	/* avoid early free in reply! */
+		lock(&listlock);
+		if(first == nil)
+			first = r;
+		else
+			last->next = r;
+		last = r;
+		unlock(&listlock);
+		r->time = nsec();
+		if(write(fd, buf, msglen) < msglen){
+			fprint(2, "%s: write failed: %r\n", argv0);
+			return;
 		}
+		seq++;
 	}
 	done = 1;
 }
@@ -172,19 +367,16 @@ sender(int fd, int msglen, int interval, int n)
 void
 rcvr(int fd, int msglen, int interval, int nmsg)
 {
-	uchar buf[64*1024+512];
-	Icmp *ip;
-	ushort x;
 	int i, n, munged;
+	ushort x;
 	vlong now;
+	uchar buf[64*1024+512];
 	Req *r;
 
-	ip = (Icmp*)buf;
 	sum = 0;
-
 	while(lostmsgs+rcvdmsgs < nmsg){
 		alarm((nmsg-lostmsgs-rcvdmsgs)*interval+5000);
-		n = read(fd, buf, sizeof(buf));
+		n = read(fd, buf, sizeof buf);
 		alarm(0);
 		now = nsec();
 		if(n <= 0){	/* read interrupted - time to go */
@@ -196,18 +388,20 @@ rcvr(int fd, int msglen, int interval, int nmsg)
 			continue;
 		}
 		munged = 0;
-		for(i = 32; i < msglen; i++)
-			if(buf[i] != (i&0xff))
+		for(i = proto->icmphdrsz; i < msglen; i++)
+			if(buf[i] != (uchar)i)
 				munged++;
 		if(munged)
-			print("currupted reply\n");
-		x = nhgets(ip->seq);
-		if(ip->type != EchoReply || ip->code != 0) {
+			print("corrupted reply\n");
+		x = (*proto->getseq)(buf);
+		if((*proto->gettype)(buf) != proto->echoreply ||
+		   (*proto->getcode)(buf) != 0) {
 			print("bad sequence/code/type %d/%d/%d\n",
-				ip->type, ip->code, x);
+				(*proto->gettype)(buf), (*proto->getcode)(buf),
+				x);
 			continue;
 		}
-		clean(x, now, ip);
+		clean(x, now, buf);
 	}
 	
 	lock(&listlock);
@@ -217,21 +411,15 @@ rcvr(int fd, int msglen, int interval, int nmsg)
 	unlock(&listlock);
 
 	if(lostmsgs)
-		print("%d out of %d messages lost\n", lostmsgs, lostmsgs+rcvdmsgs);
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-alq] [-s msgsize] [-i millisecs] [-n #pings] destination\n", argv0);
-	exits("usage");
+		print("%d out of %d messages lost\n", lostmsgs,
+			lostmsgs+rcvdmsgs);
 }
 
 void
 main(int argc, char **argv)
 {
-	int fd;
-	int msglen, interval, nmsg;
+	int fd, msglen, interval, nmsg;
+	char *ds;
 
 	nsec();		/* make sure time file is already open */
 
@@ -240,23 +428,26 @@ main(int argc, char **argv)
 	msglen = interval = 0;
 	nmsg = MAXMSG;
 	ARGBEGIN {
-	case 'l':
-		lostonly++;
+	case '6':
+		proto = &v6pr;
+		break;
+	case 'a':
+		addresses = 1;
 		break;
 	case 'd':
 		debug++;
 		break;
-	case 's':
-		msglen = atoi(ARGF());
+	case 'f':
+		flood = 1;
 		break;
 	case 'i':
-		interval = atoi(ARGF());
+		interval = atoi(EARGF(usage()));
 		break;
-	case 'n':
-		nmsg = atoi(ARGF());
+	case 'l':
+		lostonly++;
 		break;
-	case 'a':
-		addresses = 1;
+	case 'n':
+		nmsg = atoi(EARGF(usage()));
 		break;
 	case 'q':
 		quiet = 1;
@@ -264,11 +455,17 @@ main(int argc, char **argv)
 	case 'r':
 		rint = 1;
 		break;
-	case 'f':
-		flood = 1;
+	case 's':
+		msglen = atoi(EARGF(usage()));
+		break;
+	default:
+		usage();
 		break;
 	} ARGEND;
-	if(msglen < 32)
+
+	if(msglen < proto->icmphdrsz)
+		msglen = proto->icmphdrsz;
+	if(msglen < 64)
 		msglen = 64;
 	if(msglen >= 65*1024)
 		msglen = 65*1024-1;
@@ -280,17 +477,20 @@ main(int argc, char **argv)
 
 	notify(catch);
 
-	fd = dial(netmkaddr(argv[0], "icmp", "1"), 0, 0, 0);
+	ds = netmkaddr(argv[0], proto->net, "1");
+	fd = dial(ds, 0, 0, 0);
 	if(fd < 0){
-		fprint(2, "%s: couldn't dial: %r\n", argv0);
+		fprint(2, "%s: couldn't dial %s: %r\n", argv0, ds);
 		exits("dialing");
 	}
 
-	print("sending %d %d byte messages %d ms apart\n", nmsg, msglen, interval);
+	print("sending %d %d byte messages %d ms apart to %s\n",
+		nmsg, msglen, interval, ds);
 
 	switch(rfork(RFPROC|RFMEM|RFFDG)){
 	case -1:
 		fprint(2, "%s: can't fork: %r\n", argv0);
+		/* fallthrough */
 	case 0:
 		rcvr(fd, msglen, interval, nmsg);
 		exits(0);
@@ -302,36 +502,28 @@ main(int argc, char **argv)
 }
 
 void
-reply(Req *r, Icmp *ip)
+reply(Req *r, void *v)
 {
 	r->rtt /= 1000LL;
 	sum += r->rtt;
 	if(!r->replied)
 		rcvdmsgs++;
-	if(!quiet && !lostonly){
+	if(!quiet && !lostonly)
 		if(addresses)
-			print("%ud: %V->%V rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
-				r->seq-firstseq,
-				ip->src, ip->dst,
-				r->rtt, sum/rcvdmsgs, r->ttl);
+			(*proto->prreply)(r, v);
 		else
 			print("%ud: rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
-				r->seq-firstseq,
-				r->rtt, sum/rcvdmsgs, r->ttl);
-	}
+				r->seq - firstseq, r->rtt, sum/rcvdmsgs, r->ttl);
 	r->replied = 1;
 }
 
 void
-lost(Req *r, Icmp *ip)
+lost(Req *r, void *v)
 {
-	if(!quiet){
-		if(addresses && ip != nil)
-			print("lost %ud: %V->%V\n", r->seq-firstseq,
-				ip->src, ip->dst);
+	if(!quiet)
+		if(addresses && v != nil)
+			(*proto->prlost)(r->seq - firstseq, v);
 		else
-			print("lost %ud\n", r->seq-firstseq);
-	}
+			print("lost %ud\n", r->seq - firstseq);
 	lostmsgs++;
 }
-

+ 185 - 94
sys/src/cmd/tar.c

@@ -136,11 +136,12 @@ static int settime;
 static int verbose;
 static int docompress;
 static int keepexisting;
-static Off blkoff;	/* offset of the current archive block (not Tblock) */
+static int ignerrs;		/* flag: ignore i/o errors if possible */
+static Off blkoff;		/* offset of the current archive block (not Tblock) */
 static Off nexthdr;
 
 static int nblock = Dblock;
-static char *usefile;
+static char *usefile, *arname = "archive";
 static char origdir[Maxname*2];
 static Hdr *tpblk, *endblk;
 static Hdr *curblk;
@@ -148,11 +149,66 @@ static Hdr *curblk;
 static void
 usage(void)
 {
-	fprint(2, "usage: %s {crtx}[PRTfgkmpuvz] [archive] file1 file2...\n",
+	fprint(2, "usage: %s {crtx}[PRTfgikmpuvz] [archive] file1 file2...\n",
 		argv0);
 	exits("usage");
 }
 
+/* I/O, with error retry or exit */
+
+static int
+cope(char *name, int fd, void *buf, long len, Off off)
+{
+	fprint(2, "%s: %serror reading %s: %r\n", argv0,
+		(ignerrs? "ignoring ": ""), name);
+	if (!ignerrs)
+		exits("read error");
+
+	/* pretend we read len bytes of zeroes */
+	memset(buf, 0, len);
+	if (off >= 0)			/* seekable? */
+		seek(fd, off + len, 0);
+	return len;
+}
+
+static int
+eread(char *name, int fd, void *buf, long len)
+{
+	int rd;
+	Off off;
+
+	off = seek(fd, 0, 1);		/* for coping with errors */
+	rd = read(fd, buf, len);
+	if (rd < 0)
+		rd = cope(name, fd, buf, len, off);
+	return rd;
+}
+
+static int
+ereadn(char *name, int fd, void *buf, long len)
+{
+	int rd;
+	Off off;
+
+	off = seek(fd, 0, 1);
+	rd = readn(fd, buf, len);
+	if (rd < 0)
+		rd = cope(name, fd, buf, len, off);
+	return rd;
+}
+
+static int
+ewrite(char *name, int fd, void *buf, long len)
+{
+	int rd;
+
+	werrstr("");
+	rd = write(fd, buf, len);
+	if (rd != len)
+		sysfatal("error writing %s: %r", name);
+	return rd;
+}
+
 /* compression */
 
 static Compress *
@@ -260,9 +316,9 @@ refill(int ar, char *bufs, int justhdr)
 	blkoff = seek(ar, 0, 1);		/* note position for `tar r' */
 	/* try to size non-pipe input at first read */
 	if (first && usefile) {
-		n = read(ar, bufs, bytes);
-		if (n <= 0)
-			sysfatal("error reading archive: %r");
+		n = eread(arname, ar, bufs, bytes);
+		if (n == 0)
+			sysfatal("EOF reading archive: %r");
 		i = n;
 		if (i % Tblock != 0) {
 			fprint(2, "%s: archive block size (%d) error\n",
@@ -282,14 +338,12 @@ refill(int ar, char *bufs, int justhdr)
 			sysfatal("can't seek on archive: %r");
 		n = bytes;
 	} else
-		n = readn(ar, bufs, bytes);
+		n = ereadn(arname, ar, bufs, bytes);
 	first = 0;
 
 	if (n == 0)
 		sysfatal("unexpected EOF reading archive");
-	else if (n < 0)
-		sysfatal("error reading archive: %r");
-	else if (n%Tblock != 0)
+	if (n%Tblock != 0)
 		sysfatal("partial block read from archive");
 	if (n != bytes) {
 		done = 1;
@@ -355,8 +409,7 @@ putlastblk(int ar)
 	/* if writing end-of-archive, aid compression (good hygiene too) */
 	if (curblk < endblk)
 		memset(curblk, 0, (char *)endblk - (char *)curblk);
-	if (write(ar, tpblk, bytes) != bytes)
-		sysfatal("error writing archive: %r");
+	ewrite(arname, ar, tpblk, bytes);
 }
 
 static void
@@ -383,6 +436,7 @@ putreadblks(int ar, int blks)
 static void
 putblkmany(int ar, int blks)
 {
+	assert(blks > 0);
 	curblk += blks - 1;
 	putblk(ar);
 }
@@ -433,7 +487,7 @@ static char *
 name(Hdr *hp)
 {
 	int pfxlen, namlen;
-	static char fullnamebuf[2 + Maxname + 1];	/* 2 at beginning for ./ on relative names */
+	static char fullnamebuf[2+Maxname+1];  /* 2+ for ./ on relative names */
 	char *fullname;
 
 	fullname = fullnamebuf+2;
@@ -613,8 +667,8 @@ static int
 mkhdr(Hdr *hp, Dir *dir, char *file)
 {
 	/*
-	 * these fields run together, so we format them in order and don't use
-	 * snprint.
+	 * some of these fields run together, so we format them left-to-right
+	 * and don't use snprint.
 	 */
 	sprint(hp->mode, "%6lo ", dir->mode & 0777);
 	sprint(hp->uid, "%6o ", aruid);
@@ -692,8 +746,8 @@ static void
 addtoar(int ar, char *file, char *shortf)
 {
 	int n, fd, isdir;
-	long bytes;
-	ulong blksleft, blksread;
+	long bytes, blksread;
+	ulong blksleft;
 	Hdr *hbp;
 	Dir *dir;
 	String *name = nil;
@@ -737,10 +791,10 @@ addtoar(int ar, char *file, char *shortf)
 		for (; blksleft > 0; blksleft -= blksread) {
 			hbp = getblke(ar);
 			blksread = gothowmany(blksleft);
+			assert(blksread >= 0);
 			bytes = blksread * Tblock;
-			n = readn(fd, hbp->data, bytes);
-			if (n < 0)
-				sysfatal("error reading %s: %r", file);
+			n = ereadn(file, fd, hbp->data, bytes);
+			assert(n >= 0);
 			/*
 			 * ignore EOF.  zero any partial block to aid
 			 * compression and emergency recovery of data.
@@ -927,18 +981,109 @@ xaccess(char *name, int mode)
 	return rv;
 }
 
-/* copy a file from the archive into the filesystem */
-/* fname is result of name(), so has two extra bytes at beginning */
+static int
+openfname(Hdr *hp, char *fname, int dir, int mode)
+{
+	int fd;
+
+	fd = -1;
+	cleanname(fname);
+	switch (hp->linkflag) {
+	case LF_LINK:
+	case LF_SYMLINK1:
+	case LF_SYMLINK2:
+		fprint(2, "%s: can't make (sym)link %s\n",
+			argv0, fname);
+		break;
+	case LF_FIFO:
+		fprint(2, "%s: can't make fifo %s\n", argv0, fname);
+		break;
+	default:
+		if (!keepexisting || access(fname, AEXIST) < 0) {
+			int rw = (dir? OREAD: OWRITE);
+
+			fd = create(fname, rw, mode);
+			if (fd < 0) {
+				mkpdirs(fname);
+				fd = create(fname, rw, mode);
+			}
+			if (fd < 0 && (!dir || xaccess(fname, AEXIST) < 0))
+			    	cantcreate(fname, mode);
+		}
+		if (fd >= 0 && verbose)
+			fprint(2, "%s\n", fname);
+		break;
+	}
+	return fd;
+}
+
+/* copy from archive to file system (or nowhere for table-of-contents) */
+static void
+copyfromar(int ar, int fd, char *fname, ulong blksleft, Off bytes)
+{
+	int wrbytes;
+	ulong blksread;
+	Hdr *hbp;
+
+	if (blksleft == 0 || bytes < 0)
+		bytes = 0;
+	for (; blksleft > 0; blksleft -= blksread) {
+		hbp = getblkrd(ar, (fd >= 0? Alldata: Justnxthdr));
+		if (hbp == nil)
+			sysfatal("unexpected EOF on archive extracting %s",
+				fname);
+		blksread = gothowmany(blksleft);
+		if (blksread <= 0) {
+			fprint(2, "%s: got %ld blocks reading %s!\n",
+				argv0, blksread, fname);
+			blksread = 0;
+		}
+		wrbytes = Tblock*blksread;
+		assert(bytes >= 0);
+		if(wrbytes > bytes)
+			wrbytes = bytes;
+		assert(wrbytes >= 0);
+		if (fd >= 0)
+			ewrite(fname, fd, hbp->data, wrbytes);
+		putreadblks(ar, blksread);
+		bytes -= wrbytes;
+		assert(bytes >= 0);
+	}
+	if (bytes > 0)
+		fprint(2,
+	"%s: %lld bytes uncopied at EOF on archive; %s not fully extracted\n",
+			argv0, bytes, fname);
+}
+
+static void
+wrmeta(int fd, Hdr *hp, long mtime)		/* update metadata */
+{
+	Dir nd;
+
+	nulldir(&nd);
+	nd.mtime = mtime;
+	dirfwstat(fd, &nd);
+	if (isustar(hp)) {
+		nulldir(&nd);
+		nd.gid = hp->gname;
+		dirfwstat(fd, &nd);
+	}
+}
+
+/*
+ * copy a file from the archive into the filesystem.
+ * fname is result of name(), so has two extra bytes at beginning.
+ */
 static void
 extract1(int ar, Hdr *hp, char *fname)
 {
-	int wrbytes, fd = -1, dir = 0;
+	int fd = -1, dir = 0;
 	long mtime = strtol(hp->mtime, nil, 8);
 	ulong mode = strtoul(hp->mode, nil, 8) & 0777;
 	Off bytes = hdrsize(hp);		/* for printing */
-	ulong blksread, blksleft = BYTES2TBLKS(arsize(hp));
-	Hdr *hbp;
+	ulong blksleft = BYTES2TBLKS(arsize(hp));
 
+	/* fiddle name, figure out mode and blocks */
 	if (isdir(hp)) {
 		mode |= DMDIR|0700;
 		dir = 1;
@@ -951,44 +1096,17 @@ extract1(int ar, Hdr *hp, char *fname)
 		blksleft = 0;
 		break;
 	}
-	if (relative) {
+	if (relative)
 		if(fname[0] == '/')
 			*--fname = '.';
 		else if(fname[0] == '#'){
 			*--fname = '/';
 			*--fname = '.';
 		}
-	}
-	if (verb == Xtract) {
-		cleanname(fname);
-		switch (hp->linkflag) {
-		case LF_LINK:
-		case LF_SYMLINK1:
-		case LF_SYMLINK2:
-			fprint(2, "%s: can't make (sym)link %s\n",
-				argv0, fname);
-			break;
-		case LF_FIFO:
-			fprint(2, "%s: can't make fifo %s\n", argv0, fname);
-			break;
-		default:
-			if (!keepexisting || access(fname, AEXIST) < 0) {
-				int rw = (dir? OREAD: OWRITE);
 
-				fd = create(fname, rw, mode);
-				if (fd < 0) {
-					mkpdirs(fname);
-					fd = create(fname, rw, mode);
-				}
-				if (fd < 0 &&
-				    (!dir || xaccess(fname, AEXIST) < 0))
-				    	cantcreate(fname, mode);
-			}
-			if (fd >= 0 && verbose)
-				fprint(2, "%s\n", fname);
-			break;
-		}
-	} else if (verbose) {
+	if (verb == Xtract)
+		fd = openfname(hp, fname, dir, mode);
+	else if (verbose) {
 		char *cp = ctime(mtime);
 
 		print("%M %8lld %-12.12s %-4.4s %s\n",
@@ -996,46 +1114,16 @@ extract1(int ar, Hdr *hp, char *fname)
 	} else
 		print("%s\n", fname);
 
-	if (blksleft == 0)
-		bytes = 0;
-	for (; blksleft > 0; blksleft -= blksread) {
-		hbp = getblkrd(ar, (fd >= 0? Alldata: Justnxthdr));
-		if (hbp == nil)
-			sysfatal("unexpected EOF on archive extracting %s",
-				fname);
-		blksread = gothowmany(blksleft);
-		if (blksread <= 0)
-			fprint(2, "%s: got %ld blocks reading %s!\n",
-				argv0, blksread, fname);
-		wrbytes = Tblock*blksread;
-		if(wrbytes > bytes)
-			wrbytes = bytes;
-		if (fd >= 0 && write(fd, hbp->data, wrbytes) != wrbytes)
-			sysfatal("write error on %s: %r", fname);
-		putreadblks(ar, blksread);
-		bytes -= wrbytes;
-	}
-	if (bytes > 0)
-		fprint(2,
-		    "%s: %lld bytes uncopied at eof; %s not fully extracted\n",
-			argv0, bytes, fname);
+	copyfromar(ar, fd, fname, blksleft, bytes);
+
+	/* touch up meta data and close */
 	if (fd >= 0) {
 		/*
-		 * directories should be wstated after we're done
-		 * creating files in them.
+		 * directories should be wstated *after* we're done
+		 * creating files in them, but we don't do that.
 		 */
-		if (settime) {
-			Dir nd;
-
-			nulldir(&nd);
-			nd.mtime = mtime;
-			dirfwstat(fd, &nd);
-			if (isustar(hp)) {
-				nulldir(&nd);
-				nd.gid = hp->gname;
-				dirfwstat(fd, &nd);
-			}
-		}
+		if (settime)
+			wrmeta(fd, hp, mtime);
 		close(fd);
 	}
 }
@@ -1105,11 +1193,14 @@ main(int argc, char *argv[])
 		verb = Replace;
 		break;
 	case 'f':
-		usefile = EARGF(usage());
+		usefile = arname = EARGF(usage());
 		break;
 	case 'g':
 		argid = strtoul(EARGF(usage()), 0, 0);
 		break;
+	case 'i':
+		ignerrs = 1;
+		break;
 	case 'k':
 		keepexisting++;
 		break;