Browse Source

Plan 9 from Bell Labs 2007-05-22

David du Colombier 17 years ago
parent
commit
08f044643a
14 changed files with 1568 additions and 150 deletions
  1. 16 9
      dist/replica/_plan9.db
  2. 16 10
      dist/replica/plan9.db
  3. 22 0
      dist/replica/plan9.log
  4. 8 2
      rc/bin/cpurc
  5. 6 0
      rc/bin/termrc
  6. 67 10
      sys/man/1/du
  7. 141 0
      sys/man/1/ecp
  8. 88 0
      sys/man/8/6in4
  9. 8 12
      sys/src/9/port/devfs.c
  10. 207 96
      sys/src/cmd/du.c
  11. 617 0
      sys/src/cmd/ecp.c
  12. 44 10
      sys/src/cmd/import.c
  13. 327 0
      sys/src/cmd/ip/6in4.c
  14. 1 1
      sys/src/cmd/ip/traceroute.c

+ 16 - 9
dist/replica/_plan9.db

@@ -221,8 +221,9 @@
 386/bin/disk/prep - 775 sys sys 1168402303 96167
 386/bin/disk/prep - 775 sys sys 1168402303 96167
 386/bin/disk/sacfs - 775 sys sys 1020319075 79882
 386/bin/disk/sacfs - 775 sys sys 1020319075 79882
 386/bin/dossrv - 775 sys sys 1178568267 136537
 386/bin/dossrv - 775 sys sys 1178568267 136537
-386/bin/du - 775 sys sys 1168402304 74244
+386/bin/du - 775 sys sys 1179777650 76275
 386/bin/echo - 775 sys sys 1168402304 57592
 386/bin/echo - 775 sys sys 1168402304 57592
+386/bin/ecp - 775 sys sys 1179777651 72588
 386/bin/ed - 775 sys sys 1179548024 93463
 386/bin/ed - 775 sys sys 1179548024 93463
 386/bin/eqn - 775 sys sys 1173754555 244858
 386/bin/eqn - 775 sys sys 1173754555 244858
 386/bin/execnet - 775 sys sys 1179548024 176802
 386/bin/execnet - 775 sys sys 1179548024 176802
@@ -282,9 +283,10 @@
 386/bin/ico - 775 sys sys 1179372092 162180
 386/bin/ico - 775 sys sys 1179372092 162180
 386/bin/iconv - 775 sys sys 1168402316 113629
 386/bin/iconv - 775 sys sys 1168402316 113629
 386/bin/idiff - 775 sys sys 1168402317 76342
 386/bin/idiff - 775 sys sys 1168402317 76342
-386/bin/import - 775 sys sys 1179372092 101830
+386/bin/import - 775 sys sys 1179777651 102499
 386/bin/iostats - 775 sys sys 1178568280 98906
 386/bin/iostats - 775 sys sys 1178568280 98906
 386/bin/ip - 20000000775 sys sys 1016920851 0
 386/bin/ip - 20000000775 sys sys 1016920851 0
+386/bin/ip/6in4 - 775 sys sys 1179777651 88513
 386/bin/ip/dhcpclient - 775 sys sys 1178568281 92992
 386/bin/ip/dhcpclient - 775 sys sys 1178568281 92992
 386/bin/ip/dhcpd - 775 sys sys 1179458669 149879
 386/bin/ip/dhcpd - 775 sys sys 1179458669 149879
 386/bin/ip/dhcpleases - 775 sys sys 1178568281 85069
 386/bin/ip/dhcpleases - 775 sys sys 1178568281 85069
@@ -5482,7 +5484,7 @@ rc/bin/b: - 775 sys sys 1015089510 204
 rc/bin/broke - 775 sys sys 1143389260 142
 rc/bin/broke - 775 sys sys 1143389260 142
 rc/bin/bundle - 775 sys sys 945617206 173
 rc/bin/bundle - 775 sys sys 945617206 173
 rc/bin/c: - 775 sys sys 1015089511 86
 rc/bin/c: - 775 sys sys 1015089511 86
-rc/bin/cpurc - 775 sys sys 1176444833 1884
+rc/bin/cpurc - 775 sys sys 1179769494 2009
 rc/bin/cpurc.local - 775 sys sys 1176827268 367
 rc/bin/cpurc.local - 775 sys sys 1176827268 367
 rc/bin/delkey - 775 sys sys 1109429137 643
 rc/bin/delkey - 775 sys sys 1109429137 643
 rc/bin/dial - 20000000775 sys sys 1059180057 0
 rc/bin/dial - 20000000775 sys sys 1059180057 0
@@ -5606,7 +5608,7 @@ rc/bin/start - 775 sys sys 945617209 120
 rc/bin/stock - 775 sys sys 1143126371 292
 rc/bin/stock - 775 sys sys 1143126371 292
 rc/bin/stop - 775 sys sys 945617209 110
 rc/bin/stop - 775 sys sys 945617209 110
 rc/bin/tel - 775 sys sys 1161209756 128
 rc/bin/tel - 775 sys sys 1161209756 128
-rc/bin/termrc - 775 sys sys 1177705963 2281
+rc/bin/termrc - 775 sys sys 1179769653 2479
 rc/bin/termrc.local - 775 sys sys 1176500067 425
 rc/bin/termrc.local - 775 sys sys 1176500067 425
 rc/bin/thesaurus - 775 sys sys 1068054167 246
 rc/bin/thesaurus - 775 sys sys 1068054167 246
 rc/bin/tlsclienttunnel - 775 sys sys 1024375633 153
 rc/bin/tlsclienttunnel - 775 sys sys 1024375633 153
@@ -7358,8 +7360,9 @@ sys/man/1/deroff - 664 sys sys 1113743324 1826
 sys/man/1/diff - 664 sys sys 1140694865 3089
 sys/man/1/diff - 664 sys sys 1140694865 3089
 sys/man/1/doc2txt - 664 sys sys 1166761437 2304
 sys/man/1/doc2txt - 664 sys sys 1166761437 2304
 sys/man/1/doctype - 664 sys sys 1113743325 860
 sys/man/1/doctype - 664 sys sys 1113743325 860
-sys/man/1/du - 664 sys sys 1134556965 1358
+sys/man/1/du - 664 sys sys 1179726832 2281
 sys/man/1/echo - 664 sys sys 1079969656 430
 sys/man/1/echo - 664 sys sys 1079969656 430
+sys/man/1/ecp - 664 sys sys 1179725473 2576
 sys/man/1/ed - 664 sys sys 961259286 13916
 sys/man/1/ed - 664 sys sys 961259286 13916
 sys/man/1/emacs - 664 sys sys 944959673 199
 sys/man/1/emacs - 664 sys sys 944959673 199
 sys/man/1/eqn - 664 sys sys 1134592617 5655
 sys/man/1/eqn - 664 sys sys 1134592617 5655
@@ -7764,6 +7767,7 @@ sys/man/7/playlistfs - 664 sys sys 1103794042 3831
 sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/8 - 20000000775 sys sys 1162240005 0
 sys/man/8 - 20000000775 sys sys 1162240005 0
 sys/man/8/0intro - 664 sys sys 944959679 247
 sys/man/8/0intro - 664 sys sys 944959679 247
+sys/man/8/6in4 - 664 sys sys 1179779762 1655
 sys/man/8/9load - 664 sys sys 1094676489 9170
 sys/man/8/9load - 664 sys sys 1094676489 9170
 sys/man/8/9pcon - 664 sys sys 1145881850 2234
 sys/man/8/9pcon - 664 sys sys 1145881850 2234
 sys/man/8/INDEX - 664 sys sys 1178249215 2888
 sys/man/8/INDEX - 664 sys sys 1178249215 2888
@@ -8164,7 +8168,7 @@ sys/src/9/port/devcons.c - 664 sys sys 1176658321 22943
 sys/src/9/port/devdraw.c - 664 sys sys 1147023550 44447
 sys/src/9/port/devdraw.c - 664 sys sys 1147023550 44447
 sys/src/9/port/devdup.c - 664 sys sys 1014931172 2332
 sys/src/9/port/devdup.c - 664 sys sys 1014931172 2332
 sys/src/9/port/devenv.c - 664 sys sys 1169498893 7015
 sys/src/9/port/devenv.c - 664 sys sys 1169498893 7015
-sys/src/9/port/devfs.c - 664 sys sys 1179356387 12406
+sys/src/9/port/devfs.c - 664 sys sys 1179726929 12395
 sys/src/9/port/devkbmap.c - 664 sys sys 1130763846 3064
 sys/src/9/port/devkbmap.c - 664 sys sys 1130763846 3064
 sys/src/9/port/devkprof.c - 664 sys sys 1014931173 3111
 sys/src/9/port/devkprof.c - 664 sys sys 1014931173 3111
 sys/src/9/port/devloopback.c - 664 sys sys 1138458368 14579
 sys/src/9/port/devloopback.c - 664 sys sys 1138458368 14579
@@ -10224,8 +10228,9 @@ sys/src/cmd/dossrv/lock.c - 664 sys sys 954305577 504
 sys/src/cmd/dossrv/mkfile - 664 sys sys 1032057270 310
 sys/src/cmd/dossrv/mkfile - 664 sys sys 1032057270 310
 sys/src/cmd/dossrv/xfile.c - 664 sys sys 1017679315 4391
 sys/src/cmd/dossrv/xfile.c - 664 sys sys 1017679315 4391
 sys/src/cmd/dossrv/xfssrv.c - 664 sys sys 1018323479 3397
 sys/src/cmd/dossrv/xfssrv.c - 664 sys sys 1018323479 3397
-sys/src/cmd/du.c - 664 sys sys 1134659785 3421
+sys/src/cmd/du.c - 664 sys sys 1179726818 5425
 sys/src/cmd/echo.c - 664 sys sys 1081736344 581
 sys/src/cmd/echo.c - 664 sys sys 1081736344 581
+sys/src/cmd/ecp.c - 664 sys sys 1179725473 14664
 sys/src/cmd/ed.c - 664 sys sys 1143695286 21933
 sys/src/cmd/ed.c - 664 sys sys 1143695286 21933
 sys/src/cmd/eqn - 20000000775 sys sys 1055698950 0
 sys/src/cmd/eqn - 20000000775 sys sys 1055698950 0
 sys/src/cmd/eqn/diacrit.c - 664 sys sys 944960989 2302
 sys/src/cmd/eqn/diacrit.c - 664 sys sys 944960989 2302
@@ -12450,7 +12455,7 @@ sys/src/cmd/htmlroff/t9.c - 664 sys sys 1138396082 47
 sys/src/cmd/htmlroff/util.c - 664 sys sys 1138458817 1625
 sys/src/cmd/htmlroff/util.c - 664 sys sys 1138458817 1625
 sys/src/cmd/iconv.c - 664 sys sys 1039753035 1801
 sys/src/cmd/iconv.c - 664 sys sys 1039753035 1801
 sys/src/cmd/idiff.c - 664 sys sys 1014926695 6896
 sys/src/cmd/idiff.c - 664 sys sys 1014926695 6896
-sys/src/cmd/import.c - 664 sys sys 1174944074 7118
+sys/src/cmd/import.c - 664 sys sys 1179763017 7949
 sys/src/cmd/init.c - 664 sys sys 1121977160 4462
 sys/src/cmd/init.c - 664 sys sys 1121977160 4462
 sys/src/cmd/iostats - 20000000775 sys sys 1055699098 0
 sys/src/cmd/iostats - 20000000775 sys sys 1055699098 0
 sys/src/cmd/iostats/iostats.c - 664 sys sys 1140099908 10209
 sys/src/cmd/iostats/iostats.c - 664 sys sys 1140099908 10209
@@ -12458,6 +12463,7 @@ sys/src/cmd/iostats/mkfile - 664 sys sys 1014925727 122
 sys/src/cmd/iostats/statfs.h - 664 sys sys 1140099908 2626
 sys/src/cmd/iostats/statfs.h - 664 sys sys 1140099908 2626
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
+sys/src/cmd/ip/6in4.c - 664 sys sys 1179783180 7341
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
 sys/src/cmd/ip/dhcp.h - 664 sys sys 1178483074 3419
 sys/src/cmd/ip/dhcp.h - 664 sys sys 1178483074 3419
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1178482836 11969
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1178482836 11969
@@ -12603,7 +12609,7 @@ sys/src/cmd/ip/telnet.c - 664 sys sys 1162416789 8621
 sys/src/cmd/ip/telnet.h - 664 sys sys 1015090250 5902
 sys/src/cmd/ip/telnet.h - 664 sys sys 1015090250 5902
 sys/src/cmd/ip/telnetd.c - 664 sys sys 1135487948 11772
 sys/src/cmd/ip/telnetd.c - 664 sys sys 1135487948 11772
 sys/src/cmd/ip/tftpd.c - 664 sys sys 1106943821 7646
 sys/src/cmd/ip/tftpd.c - 664 sys sys 1106943821 7646
-sys/src/cmd/ip/traceroute.c - 664 sys sys 1169162086 8637
+sys/src/cmd/ip/traceroute.c - 664 sys sys 1179779560 8645
 sys/src/cmd/ip/udpecho.c - 664 sys sys 1178483004 789
 sys/src/cmd/ip/udpecho.c - 664 sys sys 1178483004 789
 sys/src/cmd/join.c - 664 sys sys 1158251357 7550
 sys/src/cmd/join.c - 664 sys sys 1158251357 7550
 sys/src/cmd/jpg - 20000000775 sys sys 1132458749 0
 sys/src/cmd/jpg - 20000000775 sys sys 1132458749 0
@@ -15832,3 +15838,4 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
+386/bin/ip/traceroute - 775 sys sys 1179804021 72750

+ 16 - 10
dist/replica/plan9.db

@@ -221,8 +221,9 @@
 386/bin/disk/prep - 775 sys sys 1168402303 96167
 386/bin/disk/prep - 775 sys sys 1168402303 96167
 386/bin/disk/sacfs - 775 sys sys 1020319075 79882
 386/bin/disk/sacfs - 775 sys sys 1020319075 79882
 386/bin/dossrv - 775 sys sys 1178568267 136537
 386/bin/dossrv - 775 sys sys 1178568267 136537
-386/bin/du - 775 sys sys 1168402304 74244
+386/bin/du - 775 sys sys 1179777650 76275
 386/bin/echo - 775 sys sys 1168402304 57592
 386/bin/echo - 775 sys sys 1168402304 57592
+386/bin/ecp - 775 sys sys 1179777651 72588
 386/bin/ed - 775 sys sys 1179548024 93463
 386/bin/ed - 775 sys sys 1179548024 93463
 386/bin/eqn - 775 sys sys 1173754555 244858
 386/bin/eqn - 775 sys sys 1173754555 244858
 386/bin/execnet - 775 sys sys 1179548024 176802
 386/bin/execnet - 775 sys sys 1179548024 176802
@@ -282,9 +283,10 @@
 386/bin/ico - 775 sys sys 1179372092 162180
 386/bin/ico - 775 sys sys 1179372092 162180
 386/bin/iconv - 775 sys sys 1168402316 113629
 386/bin/iconv - 775 sys sys 1168402316 113629
 386/bin/idiff - 775 sys sys 1168402317 76342
 386/bin/idiff - 775 sys sys 1168402317 76342
-386/bin/import - 775 sys sys 1179372092 101830
+386/bin/import - 775 sys sys 1179777651 102499
 386/bin/iostats - 775 sys sys 1178568280 98906
 386/bin/iostats - 775 sys sys 1178568280 98906
 386/bin/ip - 20000000775 sys sys 1016920851 0
 386/bin/ip - 20000000775 sys sys 1016920851 0
+386/bin/ip/6in4 - 775 sys sys 1179777651 88513
 386/bin/ip/dhcpclient - 775 sys sys 1178568281 92992
 386/bin/ip/dhcpclient - 775 sys sys 1178568281 92992
 386/bin/ip/dhcpd - 775 sys sys 1179458669 149879
 386/bin/ip/dhcpd - 775 sys sys 1179458669 149879
 386/bin/ip/dhcpleases - 775 sys sys 1178568281 85069
 386/bin/ip/dhcpleases - 775 sys sys 1178568281 85069
@@ -315,7 +317,7 @@
 386/bin/ip/rlogind - 775 sys sys 1178568290 66192
 386/bin/ip/rlogind - 775 sys sys 1178568290 66192
 386/bin/ip/telnetd - 775 sys sys 1179372096 121990
 386/bin/ip/telnetd - 775 sys sys 1179372096 121990
 386/bin/ip/tftpd - 775 sys sys 1179372096 130740
 386/bin/ip/tftpd - 775 sys sys 1179372096 130740
-386/bin/ip/traceroute - 775 sys sys 1178568291 72721
+386/bin/ip/traceroute - 775 sys sys 1179804021 72750
 386/bin/ip/udpecho - 775 sys sys 1178508500 43095
 386/bin/ip/udpecho - 775 sys sys 1178508500 43095
 386/bin/join - 775 sys sys 1168402330 114382
 386/bin/join - 775 sys sys 1168402330 114382
 386/bin/jpg - 775 sys sys 1179372097 174971
 386/bin/jpg - 775 sys sys 1179372097 174971
@@ -5482,7 +5484,7 @@ rc/bin/b: - 775 sys sys 1015089510 204
 rc/bin/broke - 775 sys sys 1143389260 142
 rc/bin/broke - 775 sys sys 1143389260 142
 rc/bin/bundle - 775 sys sys 945617206 173
 rc/bin/bundle - 775 sys sys 945617206 173
 rc/bin/c: - 775 sys sys 1015089511 86
 rc/bin/c: - 775 sys sys 1015089511 86
-rc/bin/cpurc - 775 sys sys 1176444833 1884
+rc/bin/cpurc - 775 sys sys 1179769494 2009
 rc/bin/cpurc.local - 775 sys sys 1176827268 367
 rc/bin/cpurc.local - 775 sys sys 1176827268 367
 rc/bin/delkey - 775 sys sys 1109429137 643
 rc/bin/delkey - 775 sys sys 1109429137 643
 rc/bin/dial - 20000000775 sys sys 1059180057 0
 rc/bin/dial - 20000000775 sys sys 1059180057 0
@@ -5606,7 +5608,7 @@ rc/bin/start - 775 sys sys 945617209 120
 rc/bin/stock - 775 sys sys 1143126371 292
 rc/bin/stock - 775 sys sys 1143126371 292
 rc/bin/stop - 775 sys sys 945617209 110
 rc/bin/stop - 775 sys sys 945617209 110
 rc/bin/tel - 775 sys sys 1161209756 128
 rc/bin/tel - 775 sys sys 1161209756 128
-rc/bin/termrc - 775 sys sys 1177705963 2281
+rc/bin/termrc - 775 sys sys 1179769653 2479
 rc/bin/termrc.local - 775 sys sys 1176500067 425
 rc/bin/termrc.local - 775 sys sys 1176500067 425
 rc/bin/thesaurus - 775 sys sys 1068054167 246
 rc/bin/thesaurus - 775 sys sys 1068054167 246
 rc/bin/tlsclienttunnel - 775 sys sys 1024375633 153
 rc/bin/tlsclienttunnel - 775 sys sys 1024375633 153
@@ -7358,8 +7360,9 @@ sys/man/1/deroff - 664 sys sys 1113743324 1826
 sys/man/1/diff - 664 sys sys 1140694865 3089
 sys/man/1/diff - 664 sys sys 1140694865 3089
 sys/man/1/doc2txt - 664 sys sys 1166761437 2304
 sys/man/1/doc2txt - 664 sys sys 1166761437 2304
 sys/man/1/doctype - 664 sys sys 1113743325 860
 sys/man/1/doctype - 664 sys sys 1113743325 860
-sys/man/1/du - 664 sys sys 1134556965 1358
+sys/man/1/du - 664 sys sys 1179726832 2281
 sys/man/1/echo - 664 sys sys 1079969656 430
 sys/man/1/echo - 664 sys sys 1079969656 430
+sys/man/1/ecp - 664 sys sys 1179725473 2576
 sys/man/1/ed - 664 sys sys 961259286 13916
 sys/man/1/ed - 664 sys sys 961259286 13916
 sys/man/1/emacs - 664 sys sys 944959673 199
 sys/man/1/emacs - 664 sys sys 944959673 199
 sys/man/1/eqn - 664 sys sys 1134592617 5655
 sys/man/1/eqn - 664 sys sys 1134592617 5655
@@ -7764,6 +7767,7 @@ sys/man/7/playlistfs - 664 sys sys 1103794042 3831
 sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/8 - 20000000775 sys sys 1162240005 0
 sys/man/8 - 20000000775 sys sys 1162240005 0
 sys/man/8/0intro - 664 sys sys 944959679 247
 sys/man/8/0intro - 664 sys sys 944959679 247
+sys/man/8/6in4 - 664 sys sys 1179779762 1655
 sys/man/8/9load - 664 sys sys 1094676489 9170
 sys/man/8/9load - 664 sys sys 1094676489 9170
 sys/man/8/9pcon - 664 sys sys 1145881850 2234
 sys/man/8/9pcon - 664 sys sys 1145881850 2234
 sys/man/8/INDEX - 664 sys sys 1178249215 2888
 sys/man/8/INDEX - 664 sys sys 1178249215 2888
@@ -8164,7 +8168,7 @@ sys/src/9/port/devcons.c - 664 sys sys 1176658321 22943
 sys/src/9/port/devdraw.c - 664 sys sys 1147023550 44447
 sys/src/9/port/devdraw.c - 664 sys sys 1147023550 44447
 sys/src/9/port/devdup.c - 664 sys sys 1014931172 2332
 sys/src/9/port/devdup.c - 664 sys sys 1014931172 2332
 sys/src/9/port/devenv.c - 664 sys sys 1169498893 7015
 sys/src/9/port/devenv.c - 664 sys sys 1169498893 7015
-sys/src/9/port/devfs.c - 664 sys sys 1179356387 12406
+sys/src/9/port/devfs.c - 664 sys sys 1179726929 12395
 sys/src/9/port/devkbmap.c - 664 sys sys 1130763846 3064
 sys/src/9/port/devkbmap.c - 664 sys sys 1130763846 3064
 sys/src/9/port/devkprof.c - 664 sys sys 1014931173 3111
 sys/src/9/port/devkprof.c - 664 sys sys 1014931173 3111
 sys/src/9/port/devloopback.c - 664 sys sys 1138458368 14579
 sys/src/9/port/devloopback.c - 664 sys sys 1138458368 14579
@@ -10224,8 +10228,9 @@ sys/src/cmd/dossrv/lock.c - 664 sys sys 954305577 504
 sys/src/cmd/dossrv/mkfile - 664 sys sys 1032057270 310
 sys/src/cmd/dossrv/mkfile - 664 sys sys 1032057270 310
 sys/src/cmd/dossrv/xfile.c - 664 sys sys 1017679315 4391
 sys/src/cmd/dossrv/xfile.c - 664 sys sys 1017679315 4391
 sys/src/cmd/dossrv/xfssrv.c - 664 sys sys 1018323479 3397
 sys/src/cmd/dossrv/xfssrv.c - 664 sys sys 1018323479 3397
-sys/src/cmd/du.c - 664 sys sys 1134659785 3421
+sys/src/cmd/du.c - 664 sys sys 1179726818 5425
 sys/src/cmd/echo.c - 664 sys sys 1081736344 581
 sys/src/cmd/echo.c - 664 sys sys 1081736344 581
+sys/src/cmd/ecp.c - 664 sys sys 1179725473 14664
 sys/src/cmd/ed.c - 664 sys sys 1143695286 21933
 sys/src/cmd/ed.c - 664 sys sys 1143695286 21933
 sys/src/cmd/eqn - 20000000775 sys sys 1055698950 0
 sys/src/cmd/eqn - 20000000775 sys sys 1055698950 0
 sys/src/cmd/eqn/diacrit.c - 664 sys sys 944960989 2302
 sys/src/cmd/eqn/diacrit.c - 664 sys sys 944960989 2302
@@ -12450,7 +12455,7 @@ sys/src/cmd/htmlroff/t9.c - 664 sys sys 1138396082 47
 sys/src/cmd/htmlroff/util.c - 664 sys sys 1138458817 1625
 sys/src/cmd/htmlroff/util.c - 664 sys sys 1138458817 1625
 sys/src/cmd/iconv.c - 664 sys sys 1039753035 1801
 sys/src/cmd/iconv.c - 664 sys sys 1039753035 1801
 sys/src/cmd/idiff.c - 664 sys sys 1014926695 6896
 sys/src/cmd/idiff.c - 664 sys sys 1014926695 6896
-sys/src/cmd/import.c - 664 sys sys 1174944074 7118
+sys/src/cmd/import.c - 664 sys sys 1179763017 7949
 sys/src/cmd/init.c - 664 sys sys 1121977160 4462
 sys/src/cmd/init.c - 664 sys sys 1121977160 4462
 sys/src/cmd/iostats - 20000000775 sys sys 1055699098 0
 sys/src/cmd/iostats - 20000000775 sys sys 1055699098 0
 sys/src/cmd/iostats/iostats.c - 664 sys sys 1140099908 10209
 sys/src/cmd/iostats/iostats.c - 664 sys sys 1140099908 10209
@@ -12458,6 +12463,7 @@ sys/src/cmd/iostats/mkfile - 664 sys sys 1014925727 122
 sys/src/cmd/iostats/statfs.h - 664 sys sys 1140099908 2626
 sys/src/cmd/iostats/statfs.h - 664 sys sys 1140099908 2626
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
+sys/src/cmd/ip/6in4.c - 664 sys sys 1179783180 7341
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
 sys/src/cmd/ip/dhcp.h - 664 sys sys 1178483074 3419
 sys/src/cmd/ip/dhcp.h - 664 sys sys 1178483074 3419
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1178482836 11969
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1178482836 11969
@@ -12603,7 +12609,7 @@ sys/src/cmd/ip/telnet.c - 664 sys sys 1162416789 8621
 sys/src/cmd/ip/telnet.h - 664 sys sys 1015090250 5902
 sys/src/cmd/ip/telnet.h - 664 sys sys 1015090250 5902
 sys/src/cmd/ip/telnetd.c - 664 sys sys 1135487948 11772
 sys/src/cmd/ip/telnetd.c - 664 sys sys 1135487948 11772
 sys/src/cmd/ip/tftpd.c - 664 sys sys 1106943821 7646
 sys/src/cmd/ip/tftpd.c - 664 sys sys 1106943821 7646
-sys/src/cmd/ip/traceroute.c - 664 sys sys 1169162086 8637
+sys/src/cmd/ip/traceroute.c - 664 sys sys 1179779560 8645
 sys/src/cmd/ip/udpecho.c - 664 sys sys 1178483004 789
 sys/src/cmd/ip/udpecho.c - 664 sys sys 1178483004 789
 sys/src/cmd/join.c - 664 sys sys 1158251357 7550
 sys/src/cmd/join.c - 664 sys sys 1158251357 7550
 sys/src/cmd/jpg - 20000000775 sys sys 1132458749 0
 sys/src/cmd/jpg - 20000000775 sys sys 1132458749 0

+ 22 - 0
dist/replica/plan9.log

@@ -49078,3 +49078,25 @@
 1179700222 0 c sys/src/9/ip/ipifc.c - 664 sys sys 1179700017 34199
 1179700222 0 c sys/src/9/ip/ipifc.c - 664 sys sys 1179700017 34199
 1179709223 0 c sys/man/3/ip - 664 sys sys 1179708346 24886
 1179709223 0 c sys/man/3/ip - 664 sys sys 1179708346 24886
 1179709223 1 c sys/src/9/ip/ipmux.c - 664 sys sys 1179708314 15363
 1179709223 1 c sys/src/9/ip/ipmux.c - 664 sys sys 1179708314 15363
+1179725444 0 a sys/man/1/ecp - 664 sys sys 1179725473 2576
+1179725444 1 a sys/man/8/6in4 - 664 sys sys 1179725521 1514
+1179725444 2 a sys/src/cmd/ip/6in4.c - 664 sys sys 1179725515 6941
+1179725444 3 a sys/src/cmd/ecp.c - 664 sys sys 1179725473 14664
+1179727242 0 c 386/bin/du - 775 sys sys 1179726829 76345
+1179727242 1 a 386/bin/ecp - 775 sys sys 1179725473 72658
+1179727242 2 a 386/bin/ip/6in4 - 775 sys sys 1179725607 88513
+1179727242 3 c sys/man/1/du - 664 sys sys 1179726832 2281
+1179727242 4 c sys/src/9/port/devfs.c - 664 sys sys 1179726929 12395
+1179727242 5 c sys/src/cmd/du.c - 664 sys sys 1179726818 5425
+1179763238 0 c sys/src/cmd/import.c - 664 sys sys 1179763017 7949
+1179770423 0 c rc/bin/cpurc - 775 sys sys 1179769494 2009
+1179770423 1 c rc/bin/termrc - 775 sys sys 1179769653 2479
+1179779422 0 c 386/bin/du - 775 sys sys 1179777650 76275
+1179779422 1 c 386/bin/import - 775 sys sys 1179777651 102499
+1179779422 2 c 386/bin/ecp - 775 sys sys 1179777651 72588
+1179779422 3 c 386/bin/ip/6in4 - 775 sys sys 1179777651 88513
+1179781224 0 c sys/man/8/6in4 - 664 sys sys 1179779762 1655
+1179781224 1 c sys/src/cmd/ip/6in4.c - 664 sys sys 1179779683 7114
+1179781224 2 c sys/src/cmd/ip/traceroute.c - 664 sys sys 1179779560 8645
+1179783024 0 c sys/src/cmd/ip/6in4.c - 664 sys sys 1179783180 7341
+1179804623 0 c 386/bin/ip/traceroute - 775 sys sys 1179804021 72750

+ 8 - 2
rc/bin/cpurc

@@ -12,8 +12,6 @@ sysname=`{cat /dev/sysname}
 # parallelism for mk
 # parallelism for mk
 NPROC = `{wc -l </dev/sysstat}
 NPROC = `{wc -l </dev/sysstat}
 
 
-prompt=($sysname^'# ' '	')
-
 # site-specific startup
 # site-specific startup
 if(test -e /rc/bin/cpurc.local)
 if(test -e /rc/bin/cpurc.local)
 	. /rc/bin/cpurc.local
 	. /rc/bin/cpurc.local
@@ -23,6 +21,14 @@ if(test -e /rc/bin/cpurc.local)
 # ndb/dns -s
 # ndb/dns -s
 # ip/dhcpd
 # ip/dhcpd
 # ip/tftpd
 # ip/tftpd
+
+if (~ $#sysname 0 || ~ $sysname '') {
+	sysname = helix			# default
+	echo -n $sysname >/dev/sysname
+}
+prompt=($sysname^'# ' '	')
+
+# cpu-specific startup
 if(test -e /cfg/$sysname/cpurc)
 if(test -e /cfg/$sysname/cpurc)
 	. /cfg/$sysname/cpurc
 	. /cfg/$sysname/cpurc
 
 

+ 6 - 0
rc/bin/termrc

@@ -18,6 +18,8 @@ if (! ~ $#disk 0)
 	swap $disk(1) >/dev/null >[2=1]
 	swap $disk(1) >/dev/null >[2=1]
 rm /env/disk
 rm /env/disk
 
 
+# we do this before we have a name.  we may need to do network
+# setup so that we can get a name.
 if(test -e /rc/bin/termrc.local)
 if(test -e /rc/bin/termrc.local)
 	. /rc/bin/termrc.local
 	. /rc/bin/termrc.local
 
 
@@ -25,6 +27,10 @@ if(test -e /rc/bin/termrc.local)
 if(! test -e /srv/cs)
 if(! test -e /srv/cs)
 	ndb/cs -f $NDBFILE
 	ndb/cs -f $NDBFILE
 sysname=`{cat /dev/sysname}
 sysname=`{cat /dev/sysname}
+if (~ $#sysname 0 || ~ $sysname '') {
+	sysname = gnot			# default
+	echo -n $sysname >/dev/sysname
+}
 
 
 # machine specific startup (e.g., for devices not probed)
 # machine specific startup (e.g., for devices not probed)
 if(test -e /cfg/$sysname/termrc)
 if(test -e /cfg/$sysname/termrc)

+ 67 - 10
sys/man/1/du

@@ -4,13 +4,14 @@ du \- disk usage
 .SH SYNOPSIS
 .SH SYNOPSIS
 .B du
 .B du
 [
 [
-.B -afnqstu
-]
-[
+.B -aefhnqstu
+] [
 .B -b
 .B -b
 .I size
 .I size
-]
-[
+] [
+.B -p
+.I SI-prefix
+] [
 .I file ...
 .I file ...
 ]
 ]
 .SH DESCRIPTION
 .SH DESCRIPTION
@@ -19,7 +20,7 @@ gives the number of Kbytes allocated to data blocks
 of named
 of named
 .I files
 .I files
 and, recursively, of files in named directories.
 and, recursively, of files in named directories.
-It assumes storage is quantized in units of 1024 bytes (Kbytes) by default. 
+It assumes storage is quantized in units of 1024 bytes (Kbytes) by default.
 Other values can be set by the
 Other values can be set by the
 .B -b
 .B -b
 option;
 option;
@@ -42,8 +43,7 @@ Normally counts are printed only for contained directories.
 .PP
 .PP
 The
 The
 .B -f
 .B -f
-option ignores errors,
-otherwise it stops on the first error.
+option suppresses the printing of warning messages.
 .PP
 .PP
 The
 The
 .B -n
 .B -n
@@ -66,15 +66,72 @@ The
 option prints, in the format of
 option prints, in the format of
 .B du
 .B du
 .BR -n ,
 .BR -n ,
-the QID of
+the QID path of
 each file rather than the size.
 each file rather than the size.
 .PP
 .PP
-Finally, the
+The
 .B -s
 .B -s
 option causes
 option causes
 .I du
 .I du
 to descend the hierarchy as always, but to print only a summary line
 to descend the hierarchy as always, but to print only a summary line
 for each
 for each
 .IR file .
 .IR file .
+.PP
+The
+.B -e
+option causes
+.I du
+to print values (sizes, times or QID paths)
+in `scientific notation' via
+.IR print (2)'s
+.BR %g .
+.PP
+The
+.B -h
+option causes
+.I du
+to print values (sizes, times or QID paths)
+in scientific notation,
+scaled to less than 1024, and with a suitable SI prefix
+(e.g.,
+.L G
+for binary gigabytes).
+.PP
+The
+.B -p
+option causes
+.I du
+to print values (sizes, times or QID paths)
+in units of
+.IR SI-prefix .
+Case is ignored when looking up
+.IR SI-prefix .
+An empty
+.IR SI-prefix
+corresponds to a scale factor of 1 (e.g., print sizes in bytes).
+.\" .PP
+.\" The
+.\" .B -r
+.\" option causes
+.\" .I du
+.\" to read and discard every byte of every file encountered.
+.SH EXAMPLES
+Print the size of
+.L /tmp
+in fractional binary gigabytes:
+.IP
+.EX
+% du -sepg /tmp
+\&.6960154	/tmp
+.EE
+.LP
+Print the size of
+.L /tmp
+in bytes and in scientific notation:
+.IP
+.EX
+% du -sep '' /tmp
+7.473408e+08	/tmp
+.EE
 .SH SOURCE
 .SH SOURCE
 .B /sys/src/cmd/du.c
 .B /sys/src/cmd/du.c

+ 141 - 0
sys/man/1/ecp

@@ -0,0 +1,141 @@
+.TH ECP 1
+.SH NAME
+ecp \- fast copy, handling errors
+.SH SYNOPSIS
+.in +.5i
+.ti -.5i
+.B ecp
+[
+.B \-bcprvZ
+] [
+.B \-B
+.I block-size
+] [
+.B \-e
+.I max-errors
+] [
+.B \-i
+.I issect
+] [
+.B \-o
+.I ossect
+] [
+.B \-s
+.I sector-size
+]
+.I sectors
+.I input
+.I output
+.SH DESCRIPTION
+.I Ecp
+copies
+.I sectors
+disk sectors of the specified
+.I input
+file to the specified
+.I output
+file.
+.I Ecp
+copies multiple sectors (a `block') at a time for speed.
+When
+.I ecp
+encounters an I/O error,
+it transfers the current block again,
+assuming the file is seekable,
+one sector at a time,
+prints the sector number(s) of the error(s),
+and continues copying.
+.PP
+Options are:
+.TP 4
+.B \-b
+reblock
+.IR input
+on short reads;
+this was used mainly when reading a pipe on standard input
+on 4.2+BSD systems.
+.TP
+.B \-B
+sets the block size (16,384 bytes by default) to
+.IR block-size .
+.TP
+.B \-c
+ask for confirmation on
+.B /dev/cons
+before starting the copy.
+.TP
+.B \-e
+sets a maximum number of consecutive I/O errors to permit
+at the beginning of the copy before quitting to
+.IR max-errors .
+Lots of consecutive errors may indicate a deeper problem,
+such as missing media.
+By default there is no limit.
+.TP
+.B \-i
+seeks to sector
+.I issect
+(assuming zero-origin)
+before beginning input.
+.TP
+.B \-o
+seeks to sector
+.I ossect
+(assuming zero-origin)
+before beginning output.
+.TP
+.B \-p
+print reassuring progress reports;
+helpful mainly when dealing with cranky hardware.
+.TP
+.B \-r
+copy sector groups in reverse order,
+assuming the files are seekable;
+this is most useful when
+.I input
+and
+.I output
+overlap.
+.TP
+.B \-s
+sets the sector size (512 bytes by default) to
+.IR sector-size .
+.TP
+.B \-v
+verify the copy by rereading the
+.I input
+and
+.I output
+files after copying all sectors.
+This is intended to force the disk to deliver the actual
+data written on it rather than some cached copy.
+The locations of any differences are printed.
+.TP
+.B \-Z
+`Swizzle' the input: stir the bits around in some fashion.
+Intended for diagnosing bad disks by copying a disk to itself
+a few times with swizzling on (to defeat caching in operating systems
+or disk controllers).
+.SH "SEE ALSO"
+.I fcp
+in
+.IR cp (1),
+.IR dd (1),
+.IR dup (3)
+.SH BUGS
+.BR \-i ,
+.BR \-o ,
+.BR \-r ,
+.B \-v
+and error retries only work on devices capable of seeking.
+.PP
+The set of options reflects decades of experience
+dealing with troublesome hardware.
+.PP
+If the input file is a tape and
+the last record on the tape before a file mark is less than
+.I blocksize
+bytes long,
+then
+.I ecp
+will read through past the file mark and into the next file.

+ 88 - 0
sys/man/8/6in4

@@ -0,0 +1,88 @@
+.TH 6IN4 8
+.SH NAME
+6in4 - configure and run automatic or manual 6to4 tunnel of IPv6 through IPv4
+.SH SYNOPSIS
+.B ip/6in4
+[
+.B -ag
+] [
+.B -x
+.I netmtpt
+]
+.IB local6[ / mask]
+[
+.I remote4
+[
+.I remote6
+] ]
+.B &
+.SH DESCRIPTION
+.I 6in4
+sets up and maintains a tunnel of IPv6 traffic through an IPv4 connection.
+.I Local6
+and
+.I mask
+define the IPv6 address and subnet of the near end of the tunnel
+.RI ( mask
+defaults to
+.L /128
+for a single-host
+tunnel),
+.I remote4
+is the IPv4 address of the far end of the tunnel
+(must be given explicitly for a configured tunnel, or
+defaults to the anycast address 192.88.99.1 for
+.IR 6to4 ),
+and
+.I remote6
+is the IPv6 address of the far end of the tunnel
+(used as the point-to-point destination for routing, and
+defaults to a link-local address constructed from
+.IR remote4 ).
+.PP
+Supply
+.B -g
+to use the tunnel as the default route for global IPv6 addresses.
+.B -x
+uses the network mounted at
+.I netmtpt
+instead of
+.LR /net .
+.SH EXAMPLES
+If your public IPv6 address is
+.LR 1.2.3.4,
+you can start a 6to4 tunnel simply with
+.IP
+.EX
+6in4 -g 2002:0102:0304::1/48
+.EE
+.PP
+If you use a tunnel broker at address
+.LR 5.6.7.8 , configured to
+give you a
+.L /64
+subnet with address
+.LR 2001:1122:3344:5566:: ,
+you can start the tunnel with
+.IP
+.EX
+6in4 -g 2001:1122:3344:5566::/64 5.6.7.8
+.EE
+.SH FILES
+.B /net/ipmux
+.SH SEE ALSO
+.I ipmux
+in
+.IR ip (3)
+.br
+.B /lib/rfc/rfc3056
+.br
+.B /lib/rfc/rfc3068
+.SH BUGS
+Needs a kernel with an
+.I ipmux
+driver.
+.PP
+The tunnel client filters addresses fairly conservatively in both directions.
+However it's not watertight,
+and may be flakey in other ways so don't put too much trust in it.

+ 8 - 12
sys/src/9/port/devfs.c

@@ -445,16 +445,16 @@ io(Fsdev *mp, Inner *in, int isread, void *a, long l, vlong off)
 	if (isread) {
 	if (isread) {
 		wl = devtab[mc->type]->read(mc, a, l, off);
 		wl = devtab[mc->type]->read(mc, a, l, off);
 		if (wl != l) {
 		if (wl != l) {
-			print("#k: %s byte %,lld (of %s): short read\n",
-				in->iname, off, mp->name);
-			nexterror();
+//			print("#k: %s byte %,lld (of %s): short read\n",
+//				in->iname, off, mp->name);
+			error("#k: short read");
 		}
 		}
 	} else {
 	} else {
 		wl = devtab[mc->type]->write(mc, a, l, off);
 		wl = devtab[mc->type]->write(mc, a, l, off);
 		if (wl != l) {
 		if (wl != l) {
-			print("#k: %s byte %,lld (of %s): write error\n",
-				in->iname, off, mp->name);
-			nexterror();
+//			print("#k: %s byte %,lld (of %s): write error\n",
+//				in->iname, off, mp->name);
+			error("#k: write error");
 		}
 		}
 	}
 	}
 	poperror();
 	poperror();
@@ -565,10 +565,8 @@ mread(Chan *c, void *a, long n, vlong off)
 		break;
 		break;
 	case Fmirror:
 	case Fmirror:
 		for (i = 0; i < mp->ndevs; i++){
 		for (i = 0; i < mp->ndevs; i++){
-			if (waserror()){
-				poperror();
+			if (waserror())
 				continue;
 				continue;
-			}
 			in = &mp->inner[i];
 			in = &mp->inner[i];
 			l = io(mp, in, Isread, a, n, off);
 			l = io(mp, in, Isread, a, n, off);
 			poperror();
 			poperror();
@@ -623,10 +621,8 @@ mwrite(Chan *c, void *a, long n, vlong off)
 	case Fmirror:
 	case Fmirror:
 		allbad = 1;
 		allbad = 1;
 		for (i = mp->ndevs - 1; i >= 0; i--){
 		for (i = mp->ndevs - 1; i >= 0; i--){
-			if (waserror()){
-				poperror();
+			if (waserror())
 				continue;
 				continue;
-			}
 			in = &mp->inner[i];
 			in = &mp->inner[i];
 			l = io(mp, in, Iswrite, a, n, off);
 			l = io(mp, in, Iswrite, a, n, off);
 			poperror();
 			poperror();

+ 207 - 96
sys/src/cmd/du.c

@@ -1,35 +1,79 @@
+/*
+ * du - print disk usage
+ */
 #include <u.h>
 #include <u.h>
 #include <libc.h>
 #include <libc.h>
 #include <String.h>
 #include <String.h>
 
 
 extern	vlong	du(char*, Dir*);
 extern	vlong	du(char*, Dir*);
-extern	vlong	k(vlong);
 extern	void	err(char*);
 extern	void	err(char*);
-extern	int	warn(char*);
+extern	vlong	blkmultiple(vlong);
 extern	int	seen(Dir*);
 extern	int	seen(Dir*);
+extern	int	warn(char*);
+
+enum {
+	Vkilo = 1024LL,
+};
+
+/* rounding up, how many units does amt occupy? */
+#define HOWMANY(amt, unit)	(((amt)+(unit)-1) / (unit))
+#define ROUNDUP(amt, unit)	(HOWMANY(amt, unit) * (unit))
 
 
 int	aflag;
 int	aflag;
+int	autoscale;
 int	fflag;
 int	fflag;
-int	nflag;
+int	fltflag;
+int	qflag;
+int	readflg;
 int	sflag;
 int	sflag;
 int	tflag;
 int	tflag;
 int	uflag;
 int	uflag;
-int	qflag;
+
 char	*fmt = "%llud\t%q\n";
 char	*fmt = "%llud\t%q\n";
-vlong	blocksize = 1024LL;
+char	*readbuf;
+vlong	blocksize = Vkilo;	/* actually more likely to be 4K or 8K */
+vlong	unit;			/* scale factor for output */
+
+static char *pfxes[] = {	/* SI prefixes for units > 1 */
+	"",
+	"k", "M", "G",
+	"T", "P", "E",
+	"Z", "Y",
+	nil,
+};
 
 
 void
 void
 usage(void)
 usage(void)
 {
 {
-	fprint(2, "usage: du [-afnqstu] [-b size] [file ...]\n");
+	fprint(2, "usage: du [-aefhnqstu] [-b size] [-p si-pfx] [file ...]\n");
 	exits("usage");
 	exits("usage");
 }
 }
 
 
+void
+printamt(vlong amt, char *name)
+{
+	if (readflg)
+		return;
+	if (autoscale) {
+		int scale = 0;
+		double val = (double)amt/unit;
+
+		while (fabs(val) >= 1024 && scale < nelem(pfxes)-1) {
+			scale++;
+			val /= 1024;
+		}
+		print("%.6g%s\t%q\n", val, pfxes[scale], name);
+	} else if (fltflag)
+		print("%.6g\t%q\n", (double)amt/unit, name);
+	else
+		print(fmt, HOWMANY(amt, unit), name);
+}
+
 void
 void
 main(int argc, char *argv[])
 main(int argc, char *argv[])
 {
 {
-	int i;
-	char *s, *ss;
+	int i, scale;
+	char *s, *ss, *name;
 
 
 	doquote = needsrcquote;
 	doquote = needsrcquote;
 	quotefmtinstall();
 	quotefmtinstall();
@@ -38,47 +82,135 @@ main(int argc, char *argv[])
 	case 'a':	/* all files */
 	case 'a':	/* all files */
 		aflag = 1;
 		aflag = 1;
 		break;
 		break;
-	case 's':	/* only top level */
-		sflag = 1;
+	case 'b':	/* block size */
+		s = ARGF();
+		if(s) {
+			blocksize = strtoul(s, &ss, 0);
+			if(s == ss)
+				blocksize = 1;
+			while(*ss == 'k')
+				blocksize *= 1024;
+		}
 		break;
 		break;
-	case 'f':	/* ignore errors */
+	case 'e':	/* print in %g notation */
+		fltflag = 1;
+		break;
+	case 'f':	/* don't print warnings */
 		fflag = 1;
 		fflag = 1;
 		break;
 		break;
+	case 'h':	/* similar to -h in bsd but more precise */
+		autoscale = 1;
+		break;
 	case 'n':	/* all files, number of bytes */
 	case 'n':	/* all files, number of bytes */
 		aflag = 1;
 		aflag = 1;
-		nflag = 1;
+		blocksize = 1;
+		unit = 1;
 		break;
 		break;
-	case 't':	/* return modified/accessed time */
-		tflag = 1;
-		break;
-	case 'u':	/* accessed time */
-		uflag = 1;
+	case 'p':
+		s = ARGF();
+		if(s) {
+			for (scale = 0; pfxes[scale] != nil; scale++)
+				if (cistrcmp(s, pfxes[scale]) == 0)
+					break;
+			if (pfxes[scale] == nil)
+				sysfatal("unknown suffix %s", s);
+			unit = 1;
+			while (scale-- > 0)
+				unit *= Vkilo;
+		}
 		break;
 		break;
 	case 'q':	/* qid */
 	case 'q':	/* qid */
 		fmt = "%.16llux\t%q\n";
 		fmt = "%.16llux\t%q\n";
 		qflag = 1;
 		qflag = 1;
 		break;
 		break;
-	case 'b':	/* block size */
-		s = ARGF();
-		if(s) {
-			blocksize = strtoul(s, &ss, 0);
-			if(s == ss)
-				blocksize = 1;
-			if(*ss == 'k')
-				blocksize *= 1024;
-		}
+	case 'r':
+		/* undocumented: just read & ignore every block of every file */
+		readflg = 1;
+		break;
+	case 's':	/* only top level */
+		sflag = 1;
+		break;
+	case 't':	/* return modified/accessed time */
+		tflag = 1;
+		break;
+	case 'u':	/* accessed time */
+		uflag = 1;
 		break;
 		break;
 	default:
 	default:
 		usage();
 		usage();
 	} ARGEND
 	} ARGEND
+
+	if (unit == 0)
+		if (qflag || tflag || uflag || autoscale)
+			unit = 1;
+		else
+			unit = Vkilo;
+	if (blocksize < 1)
+		blocksize = 1;
+
+	if (readflg) {
+		readbuf = malloc(blocksize);
+		if (readbuf == nil)
+			sysfatal("out of memory");
+	}
 	if(argc==0)
 	if(argc==0)
-		print(fmt, du(".", dirstat(".")), ".");
+		printamt(du(".", dirstat(".")), ".");
 	else
 	else
-		for(i=0; i<argc; i++)
-			print(fmt, du(argv[i], dirstat(argv[i])), argv[i]);
+		for(i=0; i<argc; i++) {
+			name = argv[i];
+			printamt(du(name, dirstat(name)), name);
+		}
 	exits(0);
 	exits(0);
 }
 }
 
 
+vlong
+dirval(Dir *d, vlong size)
+{
+	if(qflag)
+		return d->qid.path;
+	else if(tflag) {
+		if(uflag)
+			return d->atime;
+		return d->mtime;
+	} else
+		return size;
+}
+
+void
+readfile(char *name)
+{
+	int n, fd = open(name, OREAD);
+
+	if(fd < 0) {
+		warn(name);
+		return;
+	}
+	while ((n = read(fd, readbuf, blocksize)) > 0)
+		continue;
+	if (n < 0)
+		warn(name);
+	close(fd);
+}
+
+vlong
+dufile(char *name, Dir *d)
+{
+	vlong t = blkmultiple(d->length);
+
+	if(aflag || readflg) {
+		String *file = s_copy(name);
+
+		s_append(file, "/");
+		s_append(file, d->name);
+		if (readflg)
+			readfile(s_to_c(file));
+		t = dirval(d, t);
+		printamt(t, s_to_c(file));
+		s_free(file);
+	}
+	return t;
+}
+
 vlong
 vlong
 du(char *name, Dir *dir)
 du(char *name, Dir *dir)
 {
 {
@@ -90,80 +222,55 @@ du(char *name, Dir *dir)
 	if(dir == nil)
 	if(dir == nil)
 		return warn(name);
 		return warn(name);
 
 
+	if((dir->qid.type&QTDIR) == 0)
+		return dirval(dir, blkmultiple(dir->length));
+
 	fd = open(name, OREAD);
 	fd = open(name, OREAD);
 	if(fd < 0)
 	if(fd < 0)
 		return warn(name);
 		return warn(name);
-
-	if((dir->qid.type&QTDIR) == 0)
-		nk = k(dir->length);
-	else{
-		nk = 0;
-		while((n=dirread(fd, &buf)) > 0) {
-			d = buf;
-			for(i=0; i<n; i++, d++) {
-				if((d->qid.type&QTDIR) == 0) {
-					t = k(d->length);
-					nk += t;
-					if(aflag) {
-						file = s_copy(name);
-						s_append(file, "/");
-						s_append(file, d->name);
-						if(tflag) {
-							t = d->mtime;
-							if(uflag)
-								t = d->atime;
-						}
-						if(qflag)
-							t = d->qid.path;
-						print(fmt, t, s_to_c(file));
-						s_free(file);
-					}
-					continue;
-				}
-				if(strcmp(d->name, ".") == 0 ||
-				   strcmp(d->name, "..") == 0 ||
-				   seen(d))
-					continue;
-				file = s_copy(name);
-				s_append(file, "/");
-				s_append(file, d->name);
-				t = du(s_to_c(file), d);
-				nk += t;
-				if(tflag) {
-					t = d->mtime;
-					if(uflag)
-						t = d->atime;
-				}
-				if(qflag)
-					t = d->qid.path;
-				if(!sflag)
-					print(fmt, t, s_to_c(file));
-				s_free(file);
+	nk = 0;
+	while((n=dirread(fd, &buf)) > 0) {
+		d = buf;
+		for(i = n; i > 0; i--, d++) {
+			if((d->qid.type&QTDIR) == 0) {
+				nk += dufile(name, d);
+				continue;
 			}
 			}
-			free(buf);
+
+			if(strcmp(d->name, ".") == 0 ||
+			   strcmp(d->name, "..") == 0 ||
+			   /* !readflg && */ seen(d))
+				continue;	/* don't get stuck */
+
+			file = s_copy(name);
+			s_append(file, "/");
+			s_append(file, d->name);
+
+			t = du(s_to_c(file), d);
+
+			nk += t;
+			t = dirval(d, t);
+			if(!sflag)
+				printamt(t, s_to_c(file));
+			s_free(file);
 		}
 		}
-		if(n < 0)
-			warn(name);
+		free(buf);
 	}
 	}
+	if(n < 0)
+		warn(name);
 	close(fd);
 	close(fd);
-	if(tflag) {
-		if(uflag)
-			return dir->atime;
-		return dir->mtime;
-	}
-	if(qflag)
-		return dir->qid.path;
-	return nk;
+	return dirval(dir, nk);
 }
 }
 
 
-#define	NCACHE	128	/* must be power of two */
-typedef	struct	Cache	Cache;
-struct	Cache
+#define	NCACHE	256	/* must be power of two */
+
+typedef struct
 {
 {
 	Dir*	cache;
 	Dir*	cache;
 	int	n;
 	int	n;
 	int	max;
 	int	max;
-} cache[NCACHE];
+} Cache;
+Cache cache[NCACHE];
 
 
 int
 int
 seen(Dir *dir)
 seen(Dir *dir)
@@ -180,8 +287,12 @@ seen(Dir *dir)
 		   dir->dev == dp->dev)
 		   dir->dev == dp->dev)
 			return 1;
 			return 1;
 	if(c->n == c->max){
 	if(c->n == c->max){
-		c->cache = realloc(c->cache, (c->max+=20)*sizeof(Dir));
-		if(cache == 0)
+		if (c->max == 0)
+			c->max = 8;
+		else
+			c->max += c->max/2;
+		c->cache = realloc(c->cache, c->max*sizeof(Dir));
+		if(c->cache == nil)
 			err("malloc failure");
 			err("malloc failure");
 	}
 	}
 	c->cache[c->n++] = *dir;
 	c->cache[c->n++] = *dir;
@@ -203,11 +314,11 @@ warn(char *s)
 	return 0;
 	return 0;
 }
 }
 
 
+/* round up n to nearest block */
 vlong
 vlong
-k(vlong n)
+blkmultiple(vlong n)
 {
 {
-	if(nflag)
+	if(blocksize == 1)		/* no quantization */
 		return n;
 		return n;
-	n = (n+blocksize-1)/blocksize;
-	return n*blocksize/1024LL;
+	return ROUNDUP(n, blocksize);
 }
 }

+ 617 - 0
sys/src/cmd/ecp.c

@@ -0,0 +1,617 @@
+/*
+ * ecp - copy a file fast (in big blocks), cope with errors, optionally verify.
+ *
+ * Transfers a block at a time.  On error, retries one sector at a time,
+ * and reports all errors on the retry.
+ * Unlike dd, ecp ignores EOF, since it is sometimes reported on error.
+ * Also unlike `dd conv=noerror,sync', ecp doesn't get stuck nor give up.
+ *
+ * Written by Geoff Collyer, originally to run on RSX-11M(!) in 1979.
+ * Later simplified for UNIX and ultimately Plan 9.
+ */
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+
+/* fundamental constants */
+enum {
+	No = 0,
+	Yes,
+
+	Noseek = 0,		/* need not seek, may seek on seekable files */
+	Mustseek,
+
+	Enone = 0,
+	Eio,
+};
+
+/* tunable parameters */
+enum {
+	Defsectsz = 512,	/* default sector size */
+	/* 10K is a good size for HP WORM drives */
+	Defblksz = 16*1024,	/* default block (big-transfer) size */
+	Mingoodblks = 3,	/* after this many, go back to fast mode */
+};
+
+#define TTY "/dev/cons"			/* plan 9 */
+
+#define badsect(errno) ((errno) != Enone)  /* was last transfer in error? */
+
+/* disk address (in bytes or sectors), also type of 2nd arg. to seek */
+typedef uvlong Daddr;
+typedef vlong Sdaddr;				/* signed disk address */
+typedef long Rdwrfn(int, void *, long);		/* plan 9 read or write */
+
+typedef struct {
+	char	*name;
+	int	fd;
+	Daddr	startsect;
+	int	fast;
+	int	seekable;
+
+	ulong	maxconerrs;		/* maximum consecutive errors */
+	ulong	conerrs;		/* current consecutive errors */
+	Daddr	congoodblks;
+
+	Daddr	harderrs;
+	Daddr	lasterr;		/* sector #s */
+	Daddr	lastgood;
+} File;
+
+/* exports */
+char *argv0;
+
+/* privates */
+static int reblock = No, progress = No, swizzle = No;
+static int reverse = No;
+static ulong sectsz = Defsectsz;
+static ulong blocksize = Defblksz;
+
+static char *buf, *vfybuf;
+static int blksects;
+
+/*
+ * warning - print best error message possible and clear errno
+ */
+void
+warning(char *s1, char *s2)
+{
+	char err[100], msg[256];
+	char *np, *ep = msg + sizeof msg - 1;
+
+	errstr(err, sizeof err);		/* save error string */
+	np = seprint(msg, ep, "%s: ", argv0);
+	np = seprint(np, ep, s1, s2);
+	errstr(err, sizeof err);		/* restore error string */
+	seprint(np, ep, ": %r\n");
+
+	fprint(2, "%s", msg);
+}
+
+int
+eopen(char *file, int mode)
+{
+	int fd = open(file, mode);
+
+	if (fd < 0)
+		sysfatal("can't open %s: %r", file);
+	return fd;
+}
+
+static int					/* boolean */
+confirm(File *src, File *dest)
+{
+	int absent, n, tty = eopen(TTY, 2);
+	char c, junk;
+	Dir *stp;
+
+	if ((stp = dirstat(src->name)) == nil)
+		sysfatal("no input file %s: %r", src->name);
+	free(stp);
+	stp = dirstat(dest->name);
+	absent = (stp == nil);
+	free(stp);
+	fprint(2, "%s: copy %s to %s%s? ", argv0, src->name, dest->name,
+		(absent? " (missing)": ""));
+	n = read(tty, &c, 1);
+	junk = c;
+	if (n < 1)
+		c = 'n';
+	while (n > 0 && junk != '\n')
+		n = read(tty, &junk, 1);
+	close(tty);
+	if (isascii(c) && isupper(c))
+		c = tolower(c);
+	return c == 'y';
+}
+
+static char *
+sectid(File *fp, Daddr sect)
+{
+	static char sectname[256];
+
+	if (fp->startsect == 0)
+		snprint(sectname, sizeof sectname, "%s sector %llud",
+			fp->name, sect);
+	else
+		snprint(sectname, sizeof sectname,
+			"%s sector %llud (relative %llud)",
+			fp->name, sect + fp->startsect, sect);
+	return sectname;
+}
+
+static void
+io_expl(File *fp, char *rw, Daddr sect)		/* explain an i/o error */
+{
+	/* print only first 2 bad sectors in a range, if going forward */
+	if (reverse || fp->conerrs == 0) {
+		char msg[128];
+
+		snprint(msg, sizeof msg, "%s %s", rw, sectid(fp, sect));
+		warning("%s", msg);
+	} else if (fp->conerrs == 1)
+		fprint(2, "%s: ...\n", argv0);
+}
+
+static void
+repos(File *fp, Daddr sect)
+{
+	if (!fp->seekable)
+		sysfatal("%s: trying to seek on unseekable file", fp->name);
+	if (seek(fp->fd, (sect+fp->startsect)*sectsz, 0) == -1)
+		sysfatal("can't seek on %s: %r", fp->name);
+}
+
+static void
+rewind(File *fp)
+{
+	repos(fp, 0);
+}
+
+/*
+ * transfer (many) sectors.  reblock input as needed.
+ * returns Enone if no failures, others on failure with errstr set.
+ */
+static int
+bio(File *fp, Rdwrfn *rdwr, char *buff, Daddr stsect, int sects, int mustseek)
+{
+	int xfered;
+	ulong toread, bytes = sects * sectsz;
+	static int reblocked = 0;
+
+	if (mustseek) {
+		if (!fp->seekable)
+			sysfatal("%s: need to seek on unseekable file",
+				fp->name);
+		repos(fp, stsect);
+	}
+	if ((long)blocksize != blocksize || (long)bytes != bytes)
+		sysfatal("i/o count too big: %lud", bytes);
+
+	werrstr("");
+	xfered = (*rdwr)(fp->fd, buff, bytes);
+	if (xfered == bytes)
+		return Enone;			/* did as we asked */
+	if (xfered < 0)
+		return Eio;			/* out-and-out i/o error */
+	/*
+	 * Kernel transferred less than asked.  Shouldn't happen;
+	 * probably indicates disk driver error or trying to
+	 * transfer past the end of a disk partition.  Treat as an
+	 * I/O error that reads zeros past the point of error,
+	 * unless reblocking input and this is a read.
+	 */
+	if (rdwr == write)
+		return Eio;
+	if (!reblock) {
+		memset(buff+xfered, '\0', bytes-xfered);
+		return Eio;			/* short read */
+	}
+
+	/* for pipes that return less than asked */
+	if (progress && !reblocked) {
+		fprint(2, "%s: reblocking input\n", argv0);
+		reblocked++;
+	}
+	for (toread = bytes - xfered; toread != 0; toread -= xfered) {
+		xfered = (*rdwr)(fp->fd, buff+bytes-toread, toread);
+		if (xfered <= 0)
+			break;
+	}
+	if (xfered < 0)
+		return Eio;			/* out-and-out i/o error */
+	if (toread != 0)			/* early EOF? */
+		memset(buff+bytes-toread, '\0', toread);
+	return Enone;
+}
+
+/* called only after a single-sector transfer */
+static int
+toomanyerrs(File *fp, Daddr sect)
+{
+	if (sect == fp->lasterr+1)
+		fp->conerrs++;
+	else
+		fp->conerrs = 0;
+	fp->lasterr = sect;
+	return fp->maxconerrs != 0 && fp->conerrs >= fp->maxconerrs &&
+		fp->lastgood == -1;
+}
+
+static void
+ckendrange(File *fp)
+{
+	if (!reverse && fp->conerrs > 0)
+		fprint(2, "%s: %lld: ... last bad sector in range\n",
+			argv0, fp->lasterr);
+}
+
+static int
+transfer(File *fp, Rdwrfn *rdwr, char *buff, Daddr stsect, int sects,
+	int mustseek)
+{
+	int res = bio(fp, rdwr, buff, stsect, sects, mustseek);
+
+	if (badsect(res)) {
+		fp->fast = 0;		/* read single sectors for a while */
+		fp->congoodblks = 0;
+	} else
+		fp->lastgood = stsect + sects - 1;
+	return res;
+}
+
+/*
+ * Read or write many sectors at once.
+ * If it fails, retry the individual sectors and report errors.
+ */
+static void
+bigxfer(File *fp, Rdwrfn *rdwr, char *buff, Daddr stsect, int sects,
+	int mustseek)
+{
+	int i, badsects = 0, wasfast = fp->fast;
+	char *rw = (rdwr == read? "read": "write");
+
+	if (fp->fast) {
+		if (!badsect(transfer(fp, rdwr, buff, stsect, sects, mustseek)))
+			return;
+		if (progress)
+			fprint(2, "%s: breaking up big transfer on %s error "
+				"`%r' on %s\n", argv0, rw, sectid(fp, stsect));
+	}
+
+	for (i = 0; i < sects; i++)
+		if (badsect(transfer(fp, rdwr, buff+i*sectsz, stsect+i, 1,
+		    Mustseek))) {
+			io_expl(fp, rw, stsect+i);
+			badsects++;
+			fp->harderrs++;
+			if (toomanyerrs(fp, stsect+i))
+				sysfatal("more than %lud consecutive I/O errors",
+					fp->maxconerrs);
+		} else {
+			ckendrange(fp);
+			fp->conerrs = 0;
+		}
+	if (badsects == 0) {
+		ckendrange(fp);
+		fp->conerrs = 0;
+		if (wasfast)
+			fprint(2, "%s: %s error on big transfer at %s but none "
+				"on retries!\n", argv0, rw, sectid(fp, stsect));
+		++fp->congoodblks;
+		if (fp->congoodblks >= Mingoodblks) {
+			fprint(2, "%s: %s: back to big transfers\n", argv0,
+				fp->name);
+			fp->fast = 1;
+		}
+	} else
+		/*
+		 * the last sector could have been in error, so the seek pointer
+		 * may need to be corrected.
+		 */
+		repos(fp, stsect + sects);
+}
+
+static void
+vrfyfailed(File *src, File *dest, Daddr stsect)
+{
+	char *srcsect = strdup(sectid(src, stsect));
+
+	fprint(2, "%s: verify failed at %s (%s)\n", argv0, srcsect,
+		sectid(dest, stsect));
+	free(srcsect);
+}
+
+/*
+ * I've seen SCSI read errors that the kernel printed but then didn't
+ * report to the program doing the read, so if a big verify fails,
+ * break it up and verify each sector separately to isolate the bad sector(s).
+ */
+int						/* error count */
+verify(File *src, File *dest, char *buff, char *buft, Daddr stsect,
+	int sectors)
+{
+	int i, errors = 0;
+
+	for (i = 0; i < sectors; i++)
+		if (memcmp(buff + i*sectsz, buft + i*sectsz, sectsz) != 0)
+			errors++;
+	if (errors == 0)
+		return errors;			/* normal case */
+
+	if (sectors == 1) {
+		vrfyfailed(src, dest, stsect);
+		return errors;
+	}
+
+	/* re-read and verify each sector individually */
+	errors = 0;
+	for (i = 0; i < sectors; i++) {
+		int thissect = stsect + i;
+
+		if (badsect(bio(src,  read, buff, thissect, 1, Mustseek)))
+			io_expl(src,  "read",  thissect);
+		if (badsect(bio(dest, read, buft, thissect, 1, Mustseek)))
+			io_expl(dest, "write", thissect);
+		if (memcmp(buff, buft, sectsz) != 0) {
+			vrfyfailed(src, dest, thissect);
+			++errors;
+		}
+	}
+	if (errors == 0) {
+		char *srcsect = strdup(sectid(src, stsect));
+
+		fprint(2, "%s: verification failed on big read at %s (%s) "
+			"but not on retries!\n", argv0, srcsect,
+			sectid(dest, stsect));
+		free(srcsect);
+	}
+	/*
+	 * the last sector of each could have been in error, so the seek
+	 * pointers may need to be corrected.
+	 */
+	repos(src,  stsect + sectors);
+	repos(dest, stsect + sectors);
+	return errors;
+}
+
+/*
+ * start is starting sector of proposed transfer;
+ * nsects is the total number of sectors being copied;
+ * maxxfr is the block size in sectors.
+ */
+int
+sectsleft(Daddr start, Daddr nsects, int maxxfr)
+{
+	/* nsects-start is sectors to the end */
+	if (start + maxxfr <= nsects - 1)
+		return maxxfr;
+	else
+		return nsects - start;
+}
+
+enum {
+	Rotbits = 3,
+};
+
+void
+swizzlebits(char *buff, int sects)
+{
+	uchar *bp, *endbp;
+
+	endbp = (uchar *)(buff+sects*sectsz);
+	for (bp = (uchar *)buff; bp < endbp; bp++)
+		*bp = ~(*bp>>Rotbits | *bp<<(8-Rotbits));
+}
+
+/*
+ * copy at most blksects sectors, with error retries.
+ * stsect is relative to the start of the copy; 0 is the first sector.
+ * to get actual sector numbers, add e.g. dest->startsect.
+ */
+static int
+copysects(File *src, File *dest, Daddr stsect, Daddr nsects, int mustseek)
+{
+	int xfrsects = sectsleft(stsect, nsects, blksects);
+
+	if (xfrsects > blksects) {
+		fprint(2, "%s: block size of %d is too big.\n", argv0, xfrsects);
+		exits("block size too big");
+	}
+	bigxfer(src,  read,  buf, stsect, xfrsects, mustseek);
+	if (swizzle)
+		swizzlebits(buf, xfrsects);
+	bigxfer(dest, write, buf, stsect, xfrsects, mustseek);
+	/* give a few reassurances at the start, then every 10MB */
+	if (progress &&
+	    (stsect < blksects*10 || stsect%(10*1024*1024/sectsz) == 0))
+		fprint(2, "%s: copied%s to relative sector %llud\n", argv0,
+			(swizzle? " swizzled": ""), stsect + xfrsects - 1);
+	return 0;
+}
+
+/*
+ * verify at most blksects sectors, with error retries.
+ * return error count.
+ */
+static int
+vrfysects(File *src, File *dest, Daddr stsect, Daddr nsects, int mustseek)
+{
+	int xfrsects = sectsleft(stsect, nsects, blksects);
+
+	if (xfrsects > blksects) {
+		fprint(2, "%s: block size of %d is too big.\n", argv0, xfrsects);
+		exits("block size too big");
+	}
+	bigxfer(src,  read, buf,    stsect, xfrsects, mustseek);
+	bigxfer(dest, read, vfybuf, stsect, xfrsects, mustseek);
+	return verify(src, dest, buf, vfybuf, stsect, xfrsects);
+}
+
+static void
+setupfile(File *fp, int mode)
+{
+	fp->fd = open(fp->name, mode);
+	if (fp->fd < 0)
+		sysfatal("can't open %s: %r", fp->name);
+	fp->seekable = (seek(fp->fd, 0, 1) >= 0);
+	if (fp->startsect != 0)
+		rewind(fp);
+}
+
+static Daddr
+copyfile(File *src, File *dest, Daddr nsects, int plsverify)
+{
+	Sdaddr stsect, vererrs = 0;
+	Dir *stp;
+
+	setupfile(src, OREAD);
+	if ((stp = dirstat(dest->name)) == nil) {
+		int fd = create(dest->name, ORDWR, 0666);
+
+		if (fd >= 0)
+			close(fd);
+	}
+	free(stp);
+	setupfile(dest, ORDWR);
+
+	if (progress)
+		fprint(2, "%s: copying first sectors\n", argv0);
+	if (reverse)
+		for (stsect = (nsects/blksects)*blksects; stsect >= 0;
+		     stsect -= blksects)
+			vererrs += copysects(src, dest, stsect, nsects, Mustseek);
+	else {
+		for (stsect = 0; stsect < nsects; stsect += blksects)
+			vererrs += copysects(src, dest, stsect, nsects, Noseek);
+		ckendrange(src);
+		ckendrange(dest);
+	}
+
+	/*
+	 * verification is done as a separate pass rather than immediately after
+	 * writing, in part to defeat caching in clever disk controllers.
+	 * we really want to see the bits that hit the disk.
+	 */
+	if (plsverify) {
+		fprint(2, "%s: copy done; verifying...\n", argv0);
+		rewind(src);
+		rewind(dest);
+		for (stsect = 0; stsect < nsects; stsect += blksects) /* forward */
+			vererrs += vrfysects(src, dest, stsect, nsects, Noseek);
+		if (vererrs <= 0)
+			fprint(2, "%s: no", argv0);
+		else
+			fprint(2, "%s: %llud", argv0, vererrs);
+		fprint(2, " error%s during verification\n",
+			(vererrs != 1? "s": ""));
+	}
+	close(src->fd);
+	close(dest->fd);
+	return vererrs;
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s [-bcprvZ][-B blocksz][-e errs][-s sectsz]"
+		"[-i issect][-o ossect] sectors from to\n", argv0);
+	exits("usage");
+}
+
+void
+initfile(File *fp)
+{
+	memset(fp, 0, sizeof *fp);
+	fp->fast = 1;
+	fp->lasterr = -1;
+	fp->lastgood = -1;
+}
+
+void
+main(int argc, char **argv)
+{
+	int errflg = 0, plsconfirm = No, plsverify = No;
+	long lval;
+	File src, dest;
+	Sdaddr sect;
+
+	initfile(&src);
+	initfile(&dest);
+	ARGBEGIN {
+	case 'b':
+		reblock = Yes;
+		break;
+	case 'B':
+		lval = atol(EARGF(usage()));
+		if (lval < 0)
+			usage();
+		blocksize = lval;
+		break;
+	case 'c':
+		plsconfirm = Yes;
+		break;
+	case 'e':
+		lval = atol(EARGF(usage()));
+		if (lval < 0)
+			usage();
+		src.maxconerrs = lval;
+		dest.maxconerrs = lval;
+		break;
+	case 'i':
+		sect = atoll(EARGF(usage()));
+		if (sect < 0)
+			usage();
+		src.startsect = sect;
+		break;
+	case 'o':
+		sect = atoll(EARGF(usage()));
+		if (sect < 0)
+			usage();
+		dest.startsect = sect;
+		break;
+	case 'p':
+		progress = Yes;
+		break;
+	case 'r':
+		reverse = Yes;
+		break;
+	case 's':
+		sectsz = atol(EARGF(usage()));
+		if (sectsz <= 0 || sectsz % 512 != 0)
+			usage();
+		break;
+	case 'v':
+		plsverify = Yes;
+		break;
+	case 'Z':
+		swizzle = Yes;
+		break;
+	default:
+		errflg++;
+		break;
+	} ARGEND
+	if (errflg || argc != 3)
+		usage();
+	if (blocksize <= 0 || blocksize % sectsz != 0)
+		sysfatal("block size not a multiple of sector size");
+
+	if (!isascii(argv[0][0]) || !isdigit(argv[0][0])) {
+		fprint(2, "%s: %s is not numeric\n", argv0, argv[0]);
+		exits("non-numeric sector count");
+	}
+	src.name =  argv[1];
+	dest.name = argv[2];
+
+	blksects = blocksize / sectsz;
+	if (blksects < 1)
+		blksects = 1;
+	buf = malloc(blocksize);
+	vfybuf = malloc(blocksize);
+	if (buf == nil || vfybuf == nil)
+		sysfatal("out of memory: %r");
+
+	if (plsconfirm? confirm(&src, &dest): Yes)
+		copyfile(&src, &dest, atoll(argv[0]), plsverify);
+	exits(src.harderrs || dest.harderrs? "hard errors": 0);
+}

+ 44 - 10
sys/src/cmd/import.c

@@ -11,9 +11,9 @@ enum {
 
 
 static char *encprotos[] = {
 static char *encprotos[] = {
 	[Encnone] =	"clear",
 	[Encnone] =	"clear",
-	[Encssl] =		"ssl",
-	[Enctls] = 		"tls",
-				nil,
+	[Encssl] =	"ssl",
+	[Enctls] = 	"tls",
+			nil,
 };
 };
 
 
 char		*keyspec = "";
 char		*keyspec = "";
@@ -36,6 +36,31 @@ int	filter(int, char *, char *);
 
 
 static void	mksecret(char *, uchar *);
 static void	mksecret(char *, uchar *);
 
 
+/*
+ * based on libthread's threadsetname, but drags in less library code.
+ * actually just sets the arguments displayed.
+ */
+void
+procsetname(char *fmt, ...)
+{
+	int fd;
+	char *cmdname;
+	char buf[128];
+	va_list arg;
+
+	va_start(arg, fmt);
+	cmdname = vsmprint(fmt, arg);
+	va_end(arg);
+	if (cmdname == nil)
+		return;
+	snprint(buf, sizeof buf, "#p/%d/args", getpid());
+	if((fd = open(buf, OWRITE)) >= 0){
+		write(fd, cmdname, strlen(cmdname)+1);
+		close(fd);
+	}
+	free(cmdname);
+}
+
 void
 void
 post(char *name, char *envname, int srvfd)
 post(char *name, char *envname, int srvfd)
 {
 {
@@ -66,12 +91,10 @@ lookup(char *s, char *l[])
 void
 void
 main(int argc, char **argv)
 main(int argc, char **argv)
 {
 {
-	char *mntpt;
-	int fd, mntflags;
-	int oldserver;
-	char *srvpost, srvfile[64];
-	int backwards = 0;
+	char *mntpt, *srvpost, srvfile[64];
+	int backwards = 0, fd, mntflags, oldserver;
 
 
+	quotefmtinstall();
 	srvpost = nil;
 	srvpost = nil;
 	oldserver = 0;
 	oldserver = 0;
 	mntflags = MREPL;
 	mntflags = MREPL;
@@ -160,7 +183,8 @@ main(int argc, char **argv)
 		fd = connect(argv[0], argv[1], oldserver);
 		fd = connect(argv[0], argv[1], oldserver);
 
 
 	if (!oldserver)
 	if (!oldserver)
-		fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter", encprotos[encproto]);
+		fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter",
+			encprotos[encproto]);
 
 
 	if (encproto != Encnone && ealgs && ai) {
 	if (encproto != Encnone && ealgs && ai) {
 		uchar key[16];
 		uchar key[16];
@@ -189,6 +213,7 @@ main(int argc, char **argv)
 			fd = filter(fd, filterp, argv[0]);
 			fd = filter(fd, filterp, argv[0]);
 
 
 		/* set up encryption */
 		/* set up encryption */
+		procsetname("pushssl");
 		fd = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
 		fd = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
 		if(fd < 0)
 		if(fd < 0)
 			sysfatal("can't establish ssl connection: %r");
 			sysfatal("can't establish ssl connection: %r");
@@ -201,6 +226,7 @@ main(int argc, char **argv)
 		remove(srvfile);
 		remove(srvfile);
 		post(srvfile, srvpost, fd);
 		post(srvfile, srvpost, fd);
 	}
 	}
+	procsetname("mount on %s", mntpt);
 	if(mount(fd, -1, mntpt, mntflags, "") < 0)
 	if(mount(fd, -1, mntpt, mntflags, "") < 0)
 		sysfatal("can't mount %s: %r", argv[1]);
 		sysfatal("can't mount %s: %r", argv[1]);
 	alarm(0);
 	alarm(0);
@@ -226,6 +252,7 @@ old9p(int fd)
 {
 {
 	int p[2];
 	int p[2];
 
 
+	procsetname("old9p");
 	if(pipe(p) < 0)
 	if(pipe(p) < 0)
 		sysfatal("pipe: %r");
 		sysfatal("pipe: %r");
 
 
@@ -267,6 +294,7 @@ connect(char *system, char *tree, int oldserver)
 	char *authp;
 	char *authp;
 
 
 	na = netmkaddr(system, 0, "exportfs");
 	na = netmkaddr(system, 0, "exportfs");
+	procsetname("dial %s", na);
 	if((fd = dial(na, 0, dir, 0)) < 0)
 	if((fd = dial(na, 0, dir, 0)) < 0)
 		sysfatal("can't dial %s: %r", system);
 		sysfatal("can't dial %s: %r", system);
 
 
@@ -276,18 +304,22 @@ connect(char *system, char *tree, int oldserver)
 		else
 		else
 			authp = "p9any";
 			authp = "p9any";
 
 
+		procsetname("auth_proxy auth_getkey proto=%q role=client %s",
+			authp, keyspec);
 		ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s",
 		ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s",
 			authp, keyspec);
 			authp, keyspec);
 		if(ai == nil)
 		if(ai == nil)
 			sysfatal("%r: %s", system);
 			sysfatal("%r: %s", system);
 	}
 	}
 
 
+	procsetname("writing tree name %s", tree);
 	n = write(fd, tree, strlen(tree));
 	n = write(fd, tree, strlen(tree));
 	if(n < 0)
 	if(n < 0)
 		sysfatal("can't write tree: %r");
 		sysfatal("can't write tree: %r");
 
 
 	strcpy(buf, "can't read tree");
 	strcpy(buf, "can't read tree");
 
 
+	procsetname("awaiting OK for %s", tree);
 	n = read(fd, buf, sizeof buf - 1);
 	n = read(fd, buf, sizeof buf - 1);
 	if(n!=2 || buf[0]!='O' || buf[1]!='K'){
 	if(n!=2 || buf[0]!='O' || buf[1]!='K'){
 		if (timedout)
 		if (timedout)
@@ -310,6 +342,7 @@ passive(void)
 	 * Ignore doauth==0 on purpose.  Is it useful here?
 	 * Ignore doauth==0 on purpose.  Is it useful here?
 	 */
 	 */
 
 
+	procsetname("auth_proxy auth_getkey proto=p9any role=server");
 	ai = auth_proxy(0, auth_getkey, "proto=p9any role=server");
 	ai = auth_proxy(0, auth_getkey, "proto=p9any role=server");
 	if(ai == nil)
 	if(ai == nil)
 		sysfatal("auth_proxy: %r");
 		sysfatal("auth_proxy: %r");
@@ -329,7 +362,8 @@ passive(void)
 void
 void
 usage(void)
 usage(void)
 {
 {
-	fprint(2, "usage: import [-abcC] [-A] [-E clear|ssl|tls] [-e 'crypt auth'|clear] [-k keypattern] [-p] host remotefs [mountpoint]\n");
+	fprint(2, "usage: import [-abcC] [-A] [-E clear|ssl|tls] "
+"[-e 'crypt auth'|clear] [-k keypattern] [-p] host remotefs [mountpoint]\n");
 	exits("usage");
 	exits("usage");
 }
 }
 
 

+ 327 - 0
sys/src/cmd/ip/6in4.c

@@ -0,0 +1,327 @@
+/*
+ * 6in4 - tunnel client for automatic 6to4 or configured v6-in-v4 tunnels
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+enum {
+	IP_IPV6PROTO	= 41,
+};
+
+int anysender;
+int gateway;
+
+uchar local6[IPaddrlen];
+uchar remote6[IPaddrlen];
+uchar remote4[IPaddrlen];
+uchar localmask[IPaddrlen];
+uchar localnet[IPaddrlen];
+uchar myip[IPaddrlen];
+
+/* magic anycast address from rfc3068 */
+uchar anycast6to4[IPv4addrlen] = { 192, 88, 99, 1 };
+
+static char *net = "/net";
+
+static int	badipv4(uchar*);
+static int	badipv6(uchar*);
+static void	ip2tunnel(int, int);
+static void	tunnel2ip(int, int);
+
+static void
+usage(void)
+{
+	fprint(2, "Usage: %s [-ag] [-x mtpt] local6[/mask] [remote4 [remote6]]\n",
+		argv0);
+	exits("Usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int n, tunnel, ifc, cfd;
+	char *p, *cl, *ir;
+	char buf[128], path[64];
+
+	fmtinstall('I', eipfmt);
+	fmtinstall('V', eipfmt);
+	fmtinstall('M', eipfmt);
+
+	ARGBEGIN {
+	case 'a':
+		anysender++;
+		break;
+	case 'g':
+		gateway++;
+		break;
+	case 'x':
+		net = EARGF(usage());
+		break;
+	default:
+		usage();
+	} ARGEND
+	if (argc < 1)
+		usage();
+
+	/* local v6 address (mask defaults to /128) */
+	memcpy(localmask, IPallbits, sizeof localmask);
+	if ((p = strchr(argv[0], '/')) != nil) {
+		parseipmask(localmask, p);
+		*p = 0;
+	}
+	parseip(local6, argv[0]);
+	if (isv4(local6))
+		usage();
+	argv++;
+	argc--;
+	if (argc >= 1 && argv[0][0] == '/') {
+		parseipmask(localmask, argv[0]);
+		argv++;
+		argc--;
+	}
+
+	/* remote v4 address (defaults to anycast 6to4) */
+	if (argc >= 1) {
+		parseip(remote4, argv[0]);
+		if (!isv4(remote4))
+			usage();
+		argv++;
+		argc--;
+	} else {
+		v4tov6(remote4, anycast6to4);
+		anysender++;
+	}
+
+	/* remote v6 address (defaults to link-local w/ v4 as interface part) */
+	if (argc >= 1) {
+		parseip(remote6, argv[0]);
+		if (isv4(remote4))
+			usage();
+		argv++;
+		argc--;
+	} else {
+		remote6[0] = 0xFE;		/* link local */
+		remote6[1] = 0x80;
+		memcpy(remote6 + IPv4off, remote4 + IPv4off, IPv4addrlen);
+	}
+	USED(argv);
+	if (argc != 0)
+		usage();
+
+	maskip(local6, localmask, localnet);
+	if (myipaddr(myip, net) < 0)
+		sysfatal("can't find my ipv4 address on %s", net);
+
+	/*
+	 * open IPv6-in-IPv4 tunnel
+	 */
+	p = seprint(buf, buf + sizeof buf, "ipmux!proto=%2.2x;dst=%V",
+		IP_IPV6PROTO, myip + IPv4off);
+	if (!anysender)
+		seprint(p, buf + sizeof buf, ";src=%V", remote4 + IPv4off);
+	tunnel = dial(buf, 0, 0, 0);
+	if (tunnel < 0)
+		sysfatal("can't make 6in4 tunnel with dial str %s: %r", buf);
+
+	/*
+	 * open local IPv6 interface (as a packet interface)
+	 */
+	cl = smprint("%s/ipifc/clone", net);
+	cfd = open(cl, ORDWR);			/* allocate a conversation */
+	free(cl);
+	n = 0;
+	if (cfd < 0 || (n = read(cfd, buf, sizeof buf - 1)) <= 0)
+		sysfatal("can't make packet interface: %r");
+	buf[n] = 0;
+
+	snprint(path, sizeof path, "%s/ipifc/%s/data", net, buf);
+	ifc = open(path, ORDWR);
+	if (ifc < 0 || fprint(cfd, "bind pkt") < 0)
+		sysfatal("can't bind packet interface: %r");
+	/* 1280 is MTU, apparently from rfc2460 */
+	if (fprint(cfd, "add %I /128 %I 1280", local6, remote6) <= 0)
+		sysfatal("can't set local ipv6 address: %r");
+	close(cfd);
+
+	if (gateway) {
+		/* route global addresses through the tunnel to remote6 */
+		ir = smprint("%s/iproute", net);
+		cfd = open(ir, OWRITE);
+		free(ir);
+		if (cfd < 0 || fprint(cfd, "add 2000:: /3 %I", remote6) <= 0)
+			sysfatal("can't set default global route: %r");
+	}
+
+	switch (rfork(RFPROC|RFNOWAIT|RFMEM)) {
+	case -1:
+		sysfatal("rfork");
+	case 0:
+		ip2tunnel(ifc, tunnel);
+		break;
+	default:
+		tunnel2ip(tunnel, ifc);
+		break;
+	}
+	exits("tunnel gone");
+}
+
+typedef struct Iphdr Iphdr;
+typedef struct Ip6hdr Ip6hdr;
+
+struct Iphdr
+{
+	uchar	vihl;		/* Version and header length */
+	uchar	tos;		/* Type of service */
+	uchar	length[2];	/* packet length */
+	uchar	id[2];		/* Identification */
+	uchar	frag[2];	/* Fragment information */
+	uchar	ttl;		/* Time to live */
+	uchar	proto;		/* Protocol */
+	uchar	cksum[2];	/* Header checksum */
+	uchar	src[4];		/* Ip source (uchar ordering unimportant) */
+	uchar	dst[4];		/* Ip destination (uchar ordering unimportant) */
+};
+
+struct	Ip6hdr {
+	uchar	vcf[4];		/* version:4, traffic class:8, flow label:20 */
+	uchar	ploadlen[2];	/* payload length: packet length - 40 */
+	uchar	proto;		/* next header type */
+	uchar	ttl;		/* hop limit */
+	uchar	src[IPaddrlen];
+	uchar	dst[IPaddrlen];
+};
+
+#define STFHDR (sizeof(Iphdr))
+
+static void
+ip2tunnel(int in, int out)
+{
+	int n, m;
+	char buf[64*1024];
+	Iphdr *op;
+	Ip6hdr *ip;
+
+	op = (Iphdr*)buf;
+	op->vihl = 0x45;		/* v4, hdr is 5 longs? */
+	memcpy(op->src, myip + IPv4off, sizeof op->src);
+	op->proto = IP_IPV6PROTO;
+	op->ttl = 100;
+
+	/* get a V6 packet destined for the tunnel */
+	while ((n = read(in, buf + STFHDR, sizeof buf - STFHDR)) > 0) {
+		/* if not IPV6, drop it */
+		ip = (Ip6hdr*)(buf + STFHDR);
+		if ((ip->vcf[0]&0xF0) != 0x60)
+			continue;
+
+		/* check length: drop if too short, trim if too long */
+		m = nhgets(ip->ploadlen) + sizeof(Ip6hdr);
+		if (m > n)
+			continue;
+		if (m < n)
+			n = m;
+
+		/* drop if v6 source or destination address is naughty */
+		if (badipv6(ip->src) ||
+		    (!equivip6(ip->dst, remote6) && badipv6(ip->dst))) {
+			syslog(0, "6in4", "egress filtered %I -> %I",
+				ip->src, ip->dst);
+			continue;
+		}
+
+		/* send 6to4 packets (2002::) directly to ipv4 target */
+		if (ip->dst[0] == 0x20 && ip->dst[1] == 0x02)
+			memcpy(op->dst, ip->dst+2, sizeof op->dst);
+		else
+			memcpy(op->dst, remote4+IPv4off, sizeof op->dst);
+
+		n += STFHDR;
+		/* pass packet to the other end of the tunnel */
+		if (write(out, op, n) != n) {
+			syslog(0, "6in4", "error writing to tunnel (%r), giving up");
+			break;
+		}
+	}
+}
+
+static void
+tunnel2ip(int in, int out)
+{
+	int n, m;
+	char buf[64*1024];
+	uchar a[IPaddrlen];
+	Ip6hdr *op;
+	Iphdr *ip;
+
+	for (;;) {
+		/* get a packet from the tunnel */
+		n = read(in, buf, sizeof buf);
+		ip = (Iphdr*)(buf + IPaddrlen);
+		n -= IPaddrlen;
+		if (n <= 0) {
+			syslog(0, "6in4", "error reading from tunnel (%r), giving up");
+			break;
+		}
+
+		/* if not IPv4 nor IP protocol IPv6, drop it */
+		if ((ip->vihl&0xF0) != 0x40 || ip->proto != IP_IPV6PROTO)
+			continue;
+
+		/* check length: drop if too short, trim if too long */
+		m = nhgets(ip->length);
+		if (m > n)
+			continue;
+		if (m < n)
+			n = m;
+
+		op = (Ip6hdr*)(buf + IPaddrlen + STFHDR);
+		n -= STFHDR;
+
+		/* don't relay: just accept packets for local host/subnet */
+		/* (this blocks link-local and multicast addresses as well) */
+		maskip(op->dst, localmask, a);
+		if (!equivip6(a, localnet)) {
+			syslog(0, "6in4", "ingress filtered %I -> %I",
+				op->src, op->dst);
+			continue;
+		}
+
+		/* pass V6 packet to the interface */
+		write(out, op, n);
+	}
+}
+
+static int
+badipv4(uchar *a)
+{
+	switch (a[0]) {
+	case 0:				/* unassigned */
+	case 10:			/* private */
+	case 127:			/* loopback */
+		return 1;
+	case 172:
+		return a[1] >= 16;	/* 172.16.0.0/12 private */
+	case 192:
+		return a[1] == 168;	/* 192.168.0.0/16 private */
+	case 169:
+		return a[1] == 254;	/* 169.254.0.0/16 DHCP link-local */
+	}
+	/* 224.0.0.0/4 multicast, 240.0.0.0/4 reserved, broadcast */
+	return a[0] >= 240;
+}
+
+static int
+badipv6(uchar *a)
+{
+	int h = a[0]<<8 | a[1];
+
+	if (h == 0 ||		/* compatible, mapped, loopback, unspecified ... */
+	    h >= 0xFE80)	/* multicast, link-local or site-local */
+		return 1;
+	if (h == 0x2002 &&	/* 6to4 address */
+	    badipv4(a+2))
+		return 1;
+	return 0;
+}

+ 1 - 1
sys/src/cmd/ip/traceroute.c

@@ -364,7 +364,7 @@ main(int argc, char **argv)
 		ttl = atoi(EARGF(usage()));
 		ttl = atoi(EARGF(usage()));
 		break;
 		break;
 	case 'x':
 	case 'x':
-		net = ARGF();
+		net = EARGF(usage());
 		break;
 		break;
 	default:
 	default:
 		usage();
 		usage();