9fsys.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "stdinc.h"
  10. #include <bio.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. #include "9.h"
  14. char *foptname;
  15. struct Fsys {
  16. VtLock* lock;
  17. char* name; /* copy here & Fs to ease error reporting */
  18. char* dev;
  19. char* venti;
  20. Fs* fs;
  21. VtSession* session;
  22. int ref;
  23. int noauth;
  24. int noperm;
  25. int wstatallow;
  26. Fsys* next;
  27. };
  28. int mempcnt; /* from fossil.c */
  29. int fsGetBlockSize(Fs *fs);
  30. static struct {
  31. VtLock* lock;
  32. Fsys* head;
  33. Fsys* tail;
  34. char* curfsys;
  35. } sbox;
  36. static char *_argv0;
  37. #define argv0 _argv0
  38. static char FsysAll[] = "all";
  39. static char EFsysBusy[] = "fsys: '%s' busy";
  40. static char EFsysExists[] = "fsys: '%s' already exists";
  41. static char EFsysNoCurrent[] = "fsys: no current fsys";
  42. static char EFsysNotFound[] = "fsys: '%s' not found";
  43. static char EFsysNotOpen[] = "fsys: '%s' not open";
  44. static char *
  45. ventihost(char *host)
  46. {
  47. if(host != nil)
  48. return vtStrDup(host);
  49. host = getenv("venti");
  50. if(host == nil)
  51. host = vtStrDup("$venti");
  52. return host;
  53. }
  54. static void
  55. prventihost(char *host)
  56. {
  57. char *vh;
  58. vh = ventihost(host);
  59. fprint(2, "%s: dialing venti at %s\n",
  60. argv0, netmkaddr(vh, 0, "venti"));
  61. free(vh);
  62. }
  63. static VtSession *
  64. myDial(char *host, int canfail)
  65. {
  66. prventihost(host);
  67. return vtDial(host, canfail);
  68. }
  69. static int
  70. myRedial(VtSession *z, char *host)
  71. {
  72. prventihost(host);
  73. return vtRedial(z, host);
  74. }
  75. static Fsys*
  76. _fsysGet(char* name)
  77. {
  78. Fsys *fsys;
  79. if(name == nil || name[0] == '\0')
  80. name = "main";
  81. vtRLock(sbox.lock);
  82. for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
  83. if(strcmp(name, fsys->name) == 0){
  84. fsys->ref++;
  85. break;
  86. }
  87. }
  88. vtRUnlock(sbox.lock);
  89. if(fsys == nil)
  90. vtSetError(EFsysNotFound, name);
  91. return fsys;
  92. }
  93. static int
  94. cmdPrintConfig(int argc, char* argv[])
  95. {
  96. Fsys *fsys;
  97. char *usage = "usage: printconfig";
  98. ARGBEGIN{
  99. default:
  100. return cliError(usage);
  101. }ARGEND
  102. if(argc)
  103. return cliError(usage);
  104. vtRLock(sbox.lock);
  105. for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
  106. consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev);
  107. if(fsys->venti && fsys->venti[0])
  108. consPrint("\tfsys %s venti %q\n", fsys->name,
  109. fsys->venti);
  110. }
  111. vtRUnlock(sbox.lock);
  112. return 1;
  113. }
  114. Fsys*
  115. fsysGet(char* name)
  116. {
  117. Fsys *fsys;
  118. if((fsys = _fsysGet(name)) == nil)
  119. return nil;
  120. vtLock(fsys->lock);
  121. if(fsys->fs == nil){
  122. vtSetError(EFsysNotOpen, fsys->name);
  123. vtUnlock(fsys->lock);
  124. fsysPut(fsys);
  125. return nil;
  126. }
  127. vtUnlock(fsys->lock);
  128. return fsys;
  129. }
  130. char*
  131. fsysGetName(Fsys* fsys)
  132. {
  133. return fsys->name;
  134. }
  135. Fsys*
  136. fsysIncRef(Fsys* fsys)
  137. {
  138. vtLock(sbox.lock);
  139. fsys->ref++;
  140. vtUnlock(sbox.lock);
  141. return fsys;
  142. }
  143. void
  144. fsysPut(Fsys* fsys)
  145. {
  146. vtLock(sbox.lock);
  147. assert(fsys->ref > 0);
  148. fsys->ref--;
  149. vtUnlock(sbox.lock);
  150. }
  151. Fs*
  152. fsysGetFs(Fsys* fsys)
  153. {
  154. assert(fsys != nil && fsys->fs != nil);
  155. return fsys->fs;
  156. }
  157. void
  158. fsysFsRlock(Fsys* fsys)
  159. {
  160. vtRLock(fsys->fs->elk);
  161. }
  162. void
  163. fsysFsRUnlock(Fsys* fsys)
  164. {
  165. vtRUnlock(fsys->fs->elk);
  166. }
  167. int
  168. fsysNoAuthCheck(Fsys* fsys)
  169. {
  170. return fsys->noauth;
  171. }
  172. int
  173. fsysNoPermCheck(Fsys* fsys)
  174. {
  175. return fsys->noperm;
  176. }
  177. int
  178. fsysWstatAllow(Fsys* fsys)
  179. {
  180. return fsys->wstatallow;
  181. }
  182. static char modechars[] = "YUGalLdHSATs";
  183. static uint32_t modebits[] = {
  184. ModeSticky,
  185. ModeSetUid,
  186. ModeSetGid,
  187. ModeAppend,
  188. ModeExclusive,
  189. ModeLink,
  190. ModeDir,
  191. ModeHidden,
  192. ModeSystem,
  193. ModeArchive,
  194. ModeTemporary,
  195. ModeSnapshot,
  196. 0
  197. };
  198. char*
  199. fsysModeString(uint32_t mode, char *buf)
  200. {
  201. int i;
  202. char *p;
  203. p = buf;
  204. for(i=0; modebits[i]; i++)
  205. if(mode & modebits[i])
  206. *p++ = modechars[i];
  207. sprint(p, "%luo", mode&0777);
  208. return buf;
  209. }
  210. int
  211. fsysParseMode(char* s, uint32_t* mode)
  212. {
  213. uint32_t x, y;
  214. char *p;
  215. x = 0;
  216. for(; *s < '0' || *s > '9'; s++){
  217. if(*s == 0)
  218. return 0;
  219. p = strchr(modechars, *s);
  220. if(p == nil)
  221. return 0;
  222. x |= modebits[p-modechars];
  223. }
  224. y = strtoul(s, &p, 8);
  225. if(*p != '\0' || y > 0777)
  226. return 0;
  227. *mode = x|y;
  228. return 1;
  229. }
  230. File*
  231. fsysGetRoot(Fsys* fsys, char* name)
  232. {
  233. File *root, *sub;
  234. assert(fsys != nil && fsys->fs != nil);
  235. root = fsGetRoot(fsys->fs);
  236. if(name == nil || strcmp(name, "") == 0)
  237. return root;
  238. sub = fileWalk(root, name);
  239. fileDecRef(root);
  240. return sub;
  241. }
  242. static Fsys*
  243. fsysAlloc(char* name, char* dev)
  244. {
  245. Fsys *fsys;
  246. vtLock(sbox.lock);
  247. for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
  248. if(strcmp(fsys->name, name) != 0)
  249. continue;
  250. vtSetError(EFsysExists, name);
  251. vtUnlock(sbox.lock);
  252. return nil;
  253. }
  254. fsys = vtMemAllocZ(sizeof(Fsys));
  255. fsys->lock = vtLockAlloc();
  256. fsys->name = vtStrDup(name);
  257. fsys->dev = vtStrDup(dev);
  258. fsys->ref = 1;
  259. if(sbox.tail != nil)
  260. sbox.tail->next = fsys;
  261. else
  262. sbox.head = fsys;
  263. sbox.tail = fsys;
  264. vtUnlock(sbox.lock);
  265. return fsys;
  266. }
  267. static int
  268. fsysClose(Fsys* fsys, int argc, char* argv[])
  269. {
  270. char *usage = "usage: [fsys name] close";
  271. ARGBEGIN{
  272. default:
  273. return cliError(usage);
  274. }ARGEND
  275. if(argc)
  276. return cliError(usage);
  277. return cliError("close isn't working yet; halt %s and then kill fossil",
  278. fsys->name);
  279. /*
  280. * Oooh. This could be hard. What if fsys->ref != 1?
  281. * Also, fsClose() either does the job or panics, can we
  282. * gracefully detect it's still busy?
  283. *
  284. * More thought and care needed here.
  285. fsClose(fsys->fs);
  286. fsys->fs = nil;
  287. vtClose(fsys->session);
  288. fsys->session = nil;
  289. if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){
  290. sbox.curfsys = nil;
  291. consPrompt(nil);
  292. }
  293. return 1;
  294. */
  295. }
  296. static int
  297. fsysVac(Fsys* fsys, int argc, char* argv[])
  298. {
  299. unsigned char score[VtScoreSize];
  300. char *usage = "usage: [fsys name] vac path";
  301. ARGBEGIN{
  302. default:
  303. return cliError(usage);
  304. }ARGEND
  305. if(argc != 1)
  306. return cliError(usage);
  307. if(!fsVac(fsys->fs, argv[0], score))
  308. return 0;
  309. consPrint("vac:%V\n", score);
  310. return 1;
  311. }
  312. static int
  313. fsysSnap(Fsys* fsys, int argc, char* argv[])
  314. {
  315. int doarchive;
  316. char *usage = "usage: [fsys name] snap [-a] [-s /active] [-d /archive/yyyy/mmmm]";
  317. char *src, *dst;
  318. src = nil;
  319. dst = nil;
  320. doarchive = 0;
  321. ARGBEGIN{
  322. default:
  323. return cliError(usage);
  324. case 'a':
  325. doarchive = 1;
  326. break;
  327. case 'd':
  328. if((dst = ARGF()) == nil)
  329. return cliError(usage);
  330. break;
  331. case 's':
  332. if((src = ARGF()) == nil)
  333. return cliError(usage);
  334. break;
  335. }ARGEND
  336. if(argc)
  337. return cliError(usage);
  338. if(!fsSnapshot(fsys->fs, src, dst, doarchive))
  339. return 0;
  340. return 1;
  341. }
  342. static int
  343. fsysSnapClean(Fsys *fsys, int argc, char* argv[])
  344. {
  345. uint32_t arch, snap, life;
  346. char *usage = "usage: [fsys name] snapclean [maxminutes]\n";
  347. ARGBEGIN{
  348. default:
  349. return cliError(usage);
  350. }ARGEND
  351. if(argc > 1)
  352. return cliError(usage);
  353. if(argc == 1)
  354. life = atoi(argv[0]);
  355. else
  356. snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
  357. fsSnapshotCleanup(fsys->fs, life);
  358. return 1;
  359. }
  360. static int
  361. fsysSnapTime(Fsys* fsys, int argc, char* argv[])
  362. {
  363. char buf[128], *x;
  364. int hh, mm, changed;
  365. uint32_t arch, snap, life;
  366. char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s snapminutes] [-t maxminutes]";
  367. changed = 0;
  368. snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
  369. ARGBEGIN{
  370. case 'a':
  371. changed = 1;
  372. x = ARGF();
  373. if(x == nil)
  374. return cliError(usage);
  375. if(strcmp(x, "none") == 0){
  376. arch = ~(uint32_t)0;
  377. break;
  378. }
  379. if(strlen(x) != 4 || strspn(x, "0123456789") != 4)
  380. return cliError(usage);
  381. hh = (x[0]-'0')*10 + x[1]-'0';
  382. mm = (x[2]-'0')*10 + x[3]-'0';
  383. if(hh >= 24 || mm >= 60)
  384. return cliError(usage);
  385. arch = hh*60+mm;
  386. break;
  387. case 's':
  388. changed = 1;
  389. x = ARGF();
  390. if(x == nil)
  391. return cliError(usage);
  392. if(strcmp(x, "none") == 0){
  393. snap = ~(uint32_t)0;
  394. break;
  395. }
  396. snap = atoi(x);
  397. break;
  398. case 't':
  399. changed = 1;
  400. x = ARGF();
  401. if(x == nil)
  402. return cliError(usage);
  403. if(strcmp(x, "none") == 0){
  404. life = ~(uint32_t)0;
  405. break;
  406. }
  407. life = atoi(x);
  408. break;
  409. default:
  410. return cliError(usage);
  411. }ARGEND
  412. if(argc > 0)
  413. return cliError(usage);
  414. if(changed){
  415. snapSetTimes(fsys->fs->snap, arch, snap, life);
  416. return 1;
  417. }
  418. snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
  419. if(arch != ~(uint32_t)0)
  420. sprint(buf, "-a %02d%02d", arch/60, arch%60);
  421. else
  422. sprint(buf, "-a none");
  423. if(snap != ~(uint32_t)0)
  424. sprint(buf+strlen(buf), " -s %d", snap);
  425. else
  426. sprint(buf+strlen(buf), " -s none");
  427. if(life != ~(uint32_t)0)
  428. sprint(buf+strlen(buf), " -t %u", life);
  429. else
  430. sprint(buf+strlen(buf), " -t none");
  431. consPrint("\tsnaptime %s\n", buf);
  432. return 1;
  433. }
  434. static int
  435. fsysSync(Fsys* fsys, int argc, char* argv[])
  436. {
  437. char *usage = "usage: [fsys name] sync";
  438. int n;
  439. ARGBEGIN{
  440. default:
  441. return cliError(usage);
  442. }ARGEND
  443. if(argc > 0)
  444. return cliError(usage);
  445. n = cacheDirty(fsys->fs->cache);
  446. fsSync(fsys->fs);
  447. consPrint("\t%s sync: wrote %d blocks\n", fsys->name, n);
  448. return 1;
  449. }
  450. static int
  451. fsysHalt(Fsys *fsys, int argc, char* argv[])
  452. {
  453. char *usage = "usage: [fsys name] halt";
  454. ARGBEGIN{
  455. default:
  456. return cliError(usage);
  457. }ARGEND
  458. if(argc > 0)
  459. return cliError(usage);
  460. fsHalt(fsys->fs);
  461. return 1;
  462. }
  463. static int
  464. fsysUnhalt(Fsys *fsys, int argc, char* argv[])
  465. {
  466. char *usage = "usage: [fsys name] unhalt";
  467. ARGBEGIN{
  468. default:
  469. return cliError(usage);
  470. }ARGEND
  471. if(argc > 0)
  472. return cliError(usage);
  473. if(!fsys->fs->halted)
  474. return cliError("file system %s not halted", fsys->name);
  475. fsUnhalt(fsys->fs);
  476. return 1;
  477. }
  478. static int
  479. fsysRemove(Fsys* fsys, int argc, char* argv[])
  480. {
  481. File *file;
  482. char *usage = "usage: [fsys name] remove path ...";
  483. ARGBEGIN{
  484. default:
  485. return cliError(usage);
  486. }ARGEND
  487. if(argc == 0)
  488. return cliError(usage);
  489. vtRLock(fsys->fs->elk);
  490. while(argc > 0){
  491. if((file = fileOpen(fsys->fs, argv[0])) == nil)
  492. consPrint("%s: %R\n", argv[0]);
  493. else{
  494. if(!fileRemove(file, uidadm))
  495. consPrint("%s: %R\n", argv[0]);
  496. fileDecRef(file);
  497. }
  498. argc--;
  499. argv++;
  500. }
  501. vtRUnlock(fsys->fs->elk);
  502. return 1;
  503. }
  504. static int
  505. fsysClri(Fsys* fsys, int argc, char* argv[])
  506. {
  507. char *usage = "usage: [fsys name] clri path ...";
  508. ARGBEGIN{
  509. default:
  510. return cliError(usage);
  511. }ARGEND
  512. if(argc == 0)
  513. return cliError(usage);
  514. vtRLock(fsys->fs->elk);
  515. while(argc > 0){
  516. if(!fileClriPath(fsys->fs, argv[0], uidadm))
  517. consPrint("clri %s: %R\n", argv[0]);
  518. argc--;
  519. argv++;
  520. }
  521. vtRUnlock(fsys->fs->elk);
  522. return 1;
  523. }
  524. /*
  525. * Inspect and edit the labels for blocks on disk.
  526. */
  527. static int
  528. fsysLabel(Fsys* fsys, int argc, char* argv[])
  529. {
  530. Fs *fs;
  531. Label l;
  532. int n, r;
  533. uint32_t addr;
  534. Block *b, *bb;
  535. char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]";
  536. ARGBEGIN{
  537. default:
  538. return cliError(usage);
  539. }ARGEND
  540. if(argc != 1 && argc != 6)
  541. return cliError(usage);
  542. r = 0;
  543. vtRLock(fsys->fs->elk);
  544. fs = fsys->fs;
  545. addr = strtoul(argv[0], 0, 0);
  546. b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
  547. if(b == nil)
  548. goto Out0;
  549. l = b->l;
  550. consPrint("%slabel %#ux %u %u %u %u %#x\n",
  551. argc==6 ? "old: " : "", addr, l.type, l.state,
  552. l.epoch, l.epochClose, l.tag);
  553. if(argc == 6){
  554. if(strcmp(argv[1], "-") != 0)
  555. l.type = atoi(argv[1]);
  556. if(strcmp(argv[2], "-") != 0)
  557. l.state = atoi(argv[2]);
  558. if(strcmp(argv[3], "-") != 0)
  559. l.epoch = strtoul(argv[3], 0, 0);
  560. if(strcmp(argv[4], "-") != 0)
  561. l.epochClose = strtoul(argv[4], 0, 0);
  562. if(strcmp(argv[5], "-") != 0)
  563. l.tag = strtoul(argv[5], 0, 0);
  564. consPrint("new: label %#ux %u %u %u %u %#x\n",
  565. addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
  566. bb = _blockSetLabel(b, &l);
  567. if(bb == nil)
  568. goto Out1;
  569. n = 0;
  570. for(;;){
  571. if(blockWrite(bb, Waitlock)){
  572. while(bb->iostate != BioClean){
  573. assert(bb->iostate == BioWriting);
  574. vtSleep(bb->ioready);
  575. }
  576. break;
  577. }
  578. consPrint("blockWrite: %R\n");
  579. if(n++ >= 5){
  580. consPrint("giving up\n");
  581. break;
  582. }
  583. sleep(5*1000);
  584. }
  585. blockPut(bb);
  586. }
  587. r = 1;
  588. Out1:
  589. blockPut(b);
  590. Out0:
  591. vtRUnlock(fs->elk);
  592. return r;
  593. }
  594. /*
  595. * Inspect and edit the blocks on disk.
  596. */
  597. static int
  598. fsysBlock(Fsys* fsys, int argc, char* argv[])
  599. {
  600. Fs *fs;
  601. char *s;
  602. Block *b;
  603. unsigned char *buf;
  604. uint32_t addr;
  605. int c, count, i, offset;
  606. char *usage = "usage: [fsys name] block addr offset [count [data]]";
  607. ARGBEGIN{
  608. default:
  609. return cliError(usage);
  610. }ARGEND
  611. if(argc < 2 || argc > 4)
  612. return cliError(usage);
  613. fs = fsys->fs;
  614. addr = strtoul(argv[0], 0, 0);
  615. offset = strtoul(argv[1], 0, 0);
  616. if(offset < 0 || offset >= fs->blockSize){
  617. vtSetError("bad offset");
  618. return 0;
  619. }
  620. if(argc > 2)
  621. count = strtoul(argv[2], 0, 0);
  622. else
  623. count = 100000000;
  624. if(offset+count > fs->blockSize)
  625. count = fs->blockSize - count;
  626. vtRLock(fs->elk);
  627. b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
  628. if(b == nil){
  629. vtSetError("cacheLocal %#ux: %R", addr);
  630. vtRUnlock(fs->elk);
  631. return 0;
  632. }
  633. consPrint("\t%sblock %#ux %u %u %.*H\n",
  634. argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset);
  635. if(argc == 4){
  636. s = argv[3];
  637. if(strlen(s) != 2*count){
  638. vtSetError("bad data count");
  639. goto Out;
  640. }
  641. buf = vtMemAllocZ(count);
  642. for(i = 0; i < count*2; i++){
  643. if(s[i] >= '0' && s[i] <= '9')
  644. c = s[i] - '0';
  645. else if(s[i] >= 'a' && s[i] <= 'f')
  646. c = s[i] - 'a' + 10;
  647. else if(s[i] >= 'A' && s[i] <= 'F')
  648. c = s[i] - 'A' + 10;
  649. else{
  650. vtSetError("bad hex");
  651. vtMemFree(buf);
  652. goto Out;
  653. }
  654. if((i & 1) == 0)
  655. c <<= 4;
  656. buf[i>>1] |= c;
  657. }
  658. memmove(b->data+offset, buf, count);
  659. consPrint("\tnew: block %#ux %u %u %.*H\n",
  660. addr, offset, count, count, b->data+offset);
  661. blockDirty(b);
  662. }
  663. Out:
  664. blockPut(b);
  665. vtRUnlock(fs->elk);
  666. return 1;
  667. }
  668. /*
  669. * Free a disk block.
  670. */
  671. static int
  672. fsysBfree(Fsys* fsys, int argc, char* argv[])
  673. {
  674. Fs *fs;
  675. Label l;
  676. char *p;
  677. Block *b;
  678. uint32_t addr;
  679. char *usage = "usage: [fsys name] bfree addr ...";
  680. ARGBEGIN{
  681. default:
  682. return cliError(usage);
  683. }ARGEND
  684. if(argc == 0)
  685. return cliError(usage);
  686. fs = fsys->fs;
  687. vtRLock(fs->elk);
  688. while(argc > 0){
  689. addr = strtoul(argv[0], &p, 0);
  690. if(*p != '\0'){
  691. consPrint("bad address - '%u'\n", addr);
  692. /* syntax error; let's stop */
  693. vtRUnlock(fs->elk);
  694. return 0;
  695. }
  696. b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
  697. if(b == nil){
  698. consPrint("loading %#ux: %R\n", addr);
  699. continue;
  700. }
  701. l = b->l;
  702. if(l.state == BsFree)
  703. consPrint("%#ux is already free\n", addr);
  704. else{
  705. consPrint("label %#ux %u %u %u %u %#x\n",
  706. addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
  707. l.state = BsFree;
  708. l.type = BtMax;
  709. l.tag = 0;
  710. l.epoch = 0;
  711. l.epochClose = 0;
  712. if(!blockSetLabel(b, &l, 0))
  713. consPrint("freeing %#ux: %R\n", addr);
  714. }
  715. blockPut(b);
  716. argc--;
  717. argv++;
  718. }
  719. vtRUnlock(fs->elk);
  720. return 1;
  721. }
  722. static int
  723. fsysDf(Fsys *fsys, int argc, char* argv[])
  724. {
  725. char *usage = "usage: [fsys name] df";
  726. uint32_t used, tot, bsize;
  727. Fs *fs;
  728. ARGBEGIN{
  729. default:
  730. return cliError(usage);
  731. }ARGEND
  732. if(argc != 0)
  733. return cliError(usage);
  734. fs = fsys->fs;
  735. cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize);
  736. consPrint("\t%s: %,llud used + %,llud free = %,llud (%.1f%% used)\n",
  737. fsys->name, used*(int64_t)bsize, (tot-used)*(int64_t)bsize,
  738. tot*(int64_t)bsize, used*100.0/tot);
  739. return 1;
  740. }
  741. /*
  742. * Zero an entry or a pointer.
  743. */
  744. static int
  745. fsysClrep(Fsys* fsys, int argc, char* argv[], int ch)
  746. {
  747. Fs *fs;
  748. Entry e;
  749. Block *b;
  750. uint32_t addr;
  751. int i, max, offset, sz;
  752. unsigned char zero[VtEntrySize];
  753. char *usage = "usage: [fsys name] clr%c addr offset ...";
  754. ARGBEGIN{
  755. default:
  756. return cliError(usage, ch);
  757. }ARGEND
  758. if(argc < 2)
  759. return cliError(usage, ch);
  760. fs = fsys->fs;
  761. vtRLock(fsys->fs->elk);
  762. addr = strtoul(argv[0], 0, 0);
  763. b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
  764. if(b == nil){
  765. vtSetError("cacheLocal %#ux: %R", addr);
  766. Err:
  767. vtRUnlock(fsys->fs->elk);
  768. return 0;
  769. }
  770. switch(ch){
  771. default:
  772. vtSetError("clrep");
  773. goto Err;
  774. case 'e':
  775. if(b->l.type != BtDir){
  776. vtSetError("wrong block type");
  777. goto Err;
  778. }
  779. sz = VtEntrySize;
  780. memset(&e, 0, sizeof e);
  781. entryPack(&e, zero, 0);
  782. break;
  783. case 'p':
  784. if(b->l.type == BtDir || b->l.type == BtData){
  785. vtSetError("wrong block type");
  786. goto Err;
  787. }
  788. sz = VtScoreSize;
  789. memmove(zero, vtZeroScore, VtScoreSize);
  790. break;
  791. }
  792. max = fs->blockSize/sz;
  793. for(i = 1; i < argc; i++){
  794. offset = atoi(argv[i]);
  795. if(offset >= max){
  796. consPrint("\toffset %d too large (>= %d)\n", i, max);
  797. continue;
  798. }
  799. consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz);
  800. memmove(b->data+offset*sz, zero, sz);
  801. }
  802. blockDirty(b);
  803. blockPut(b);
  804. vtRUnlock(fsys->fs->elk);
  805. return 1;
  806. }
  807. static int
  808. fsysClre(Fsys* fsys, int argc, char* argv[])
  809. {
  810. return fsysClrep(fsys, argc, argv, 'e');
  811. }
  812. static int
  813. fsysClrp(Fsys* fsys, int argc, char* argv[])
  814. {
  815. return fsysClrep(fsys, argc, argv, 'p');
  816. }
  817. static int
  818. fsysEsearch1(File* f, char* s, uint32_t elo)
  819. {
  820. int n, r;
  821. DirEntry de;
  822. DirEntryEnum *dee;
  823. File *ff;
  824. Entry e, ee;
  825. char *t;
  826. dee = deeOpen(f);
  827. if(dee == nil)
  828. return 0;
  829. n = 0;
  830. for(;;){
  831. r = deeRead(dee, &de);
  832. if(r < 0){
  833. consPrint("\tdeeRead %s/%s: %R\n", s, de.elem);
  834. break;
  835. }
  836. if(r == 0)
  837. break;
  838. if(de.mode & ModeSnapshot){
  839. if((ff = fileWalk(f, de.elem)) == nil)
  840. consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
  841. else{
  842. if(!fileGetSources(ff, &e, &ee))
  843. consPrint("\tcannot get sources for %s/%s: %R\n", s, de.elem);
  844. else if(e.snap != 0 && e.snap < elo){
  845. consPrint("\t%u\tclri %s/%s\n", e.snap, s, de.elem);
  846. n++;
  847. }
  848. fileDecRef(ff);
  849. }
  850. }
  851. else if(de.mode & ModeDir){
  852. if((ff = fileWalk(f, de.elem)) == nil)
  853. consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
  854. else{
  855. t = smprint("%s/%s", s, de.elem);
  856. n += fsysEsearch1(ff, t, elo);
  857. vtMemFree(t);
  858. fileDecRef(ff);
  859. }
  860. }
  861. deCleanup(&de);
  862. if(r < 0)
  863. break;
  864. }
  865. deeClose(dee);
  866. return n;
  867. }
  868. static int
  869. fsysEsearch(Fs* fs, char* path, uint32_t elo)
  870. {
  871. int n;
  872. File *f;
  873. DirEntry de;
  874. f = fileOpen(fs, path);
  875. if(f == nil)
  876. return 0;
  877. if(!fileGetDir(f, &de)){
  878. consPrint("\tfileGetDir %s failed: %R\n", path);
  879. fileDecRef(f);
  880. return 0;
  881. }
  882. if((de.mode & ModeDir) == 0){
  883. fileDecRef(f);
  884. deCleanup(&de);
  885. return 0;
  886. }
  887. deCleanup(&de);
  888. n = fsysEsearch1(f, path, elo);
  889. fileDecRef(f);
  890. return n;
  891. }
  892. static int
  893. fsysEpoch(Fsys* fsys, int argc, char* argv[])
  894. {
  895. Fs *fs;
  896. int force, n, remove;
  897. uint32_t low, old;
  898. char *usage = "usage: [fsys name] epoch [[-ry] low]";
  899. force = 0;
  900. remove = 0;
  901. ARGBEGIN{
  902. case 'y':
  903. force = 1;
  904. break;
  905. case 'r':
  906. remove = 1;
  907. break;
  908. default:
  909. return cliError(usage);
  910. }ARGEND
  911. if(argc > 1)
  912. return cliError(usage);
  913. if(argc > 0)
  914. low = strtoul(argv[0], 0, 0);
  915. else
  916. low = ~(uint32_t)0;
  917. if(low == 0)
  918. return cliError("low epoch cannot be zero");
  919. fs = fsys->fs;
  920. vtRLock(fs->elk);
  921. consPrint("\tlow %u hi %u\n", fs->elo, fs->ehi);
  922. if(low == ~(uint32_t)0){
  923. vtRUnlock(fs->elk);
  924. return 1;
  925. }
  926. n = fsysEsearch(fsys->fs, "/archive", low);
  927. n += fsysEsearch(fsys->fs, "/snapshot", low);
  928. consPrint("\t%d snapshot%s found with epoch < %u\n", n, n==1 ? "" : "s", low);
  929. vtRUnlock(fs->elk);
  930. /*
  931. * There's a small race here -- a new snapshot with epoch < low might
  932. * get introduced now that we unlocked fs->elk. Low has to
  933. * be <= fs->ehi. Of course, in order for this to happen low has
  934. * to be equal to the current fs->ehi _and_ a snapshot has to
  935. * run right now. This is a small enough window that I don't care.
  936. */
  937. if(n != 0 && !force){
  938. consPrint("\tnot setting low epoch\n");
  939. return 1;
  940. }
  941. old = fs->elo;
  942. if(!fsEpochLow(fs, low))
  943. consPrint("\tfsEpochLow: %R\n");
  944. else{
  945. consPrint("\told: epoch%s %u\n", force ? " -y" : "", old);
  946. consPrint("\tnew: epoch%s %u\n", force ? " -y" : "", fs->elo);
  947. if(fs->elo < low)
  948. consPrint("\twarning: new low epoch < old low epoch\n");
  949. if(force && remove)
  950. fsSnapshotRemove(fs);
  951. }
  952. return 1;
  953. }
  954. static int
  955. fsysCreate(Fsys* fsys, int argc, char* argv[])
  956. {
  957. int r;
  958. uint32_t mode;
  959. char *elem, *p, *path;
  960. char *usage = "usage: [fsys name] create path uid gid perm";
  961. DirEntry de;
  962. File *file, *parent;
  963. ARGBEGIN{
  964. default:
  965. return cliError(usage);
  966. }ARGEND
  967. if(argc != 4)
  968. return cliError(usage);
  969. if(!fsysParseMode(argv[3], &mode))
  970. return cliError(usage);
  971. if(mode&ModeSnapshot)
  972. return cliError("create - cannot create with snapshot bit set");
  973. if(strcmp(argv[1], uidnoworld) == 0)
  974. return cliError("permission denied");
  975. vtRLock(fsys->fs->elk);
  976. path = vtStrDup(argv[0]);
  977. if((p = strrchr(path, '/')) != nil){
  978. *p++ = '\0';
  979. elem = p;
  980. p = path;
  981. if(*p == '\0')
  982. p = "/";
  983. }
  984. else{
  985. p = "/";
  986. elem = path;
  987. }
  988. r = 0;
  989. if((parent = fileOpen(fsys->fs, p)) == nil)
  990. goto out;
  991. file = fileCreate(parent, elem, mode, argv[1]);
  992. fileDecRef(parent);
  993. if(file == nil){
  994. vtSetError("create %s/%s: %R", p, elem);
  995. goto out;
  996. }
  997. if(!fileGetDir(file, &de)){
  998. vtSetError("stat failed after create: %R");
  999. goto out1;
  1000. }
  1001. if(strcmp(de.gid, argv[2]) != 0){
  1002. vtMemFree(de.gid);
  1003. de.gid = vtStrDup(argv[2]);
  1004. if(!fileSetDir(file, &de, argv[1])){
  1005. vtSetError("wstat failed after create: %R");
  1006. goto out2;
  1007. }
  1008. }
  1009. r = 1;
  1010. out2:
  1011. deCleanup(&de);
  1012. out1:
  1013. fileDecRef(file);
  1014. out:
  1015. vtMemFree(path);
  1016. vtRUnlock(fsys->fs->elk);
  1017. return r;
  1018. }
  1019. static void
  1020. fsysPrintStat(char *prefix, char *file, DirEntry *de)
  1021. {
  1022. char buf[64];
  1023. if(prefix == nil)
  1024. prefix = "";
  1025. consPrint("%sstat %q %q %q %q %s %llu\n", prefix,
  1026. file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size);
  1027. }
  1028. static int
  1029. fsysStat(Fsys* fsys, int argc, char* argv[])
  1030. {
  1031. int i;
  1032. File *f;
  1033. DirEntry de;
  1034. char *usage = "usage: [fsys name] stat files...";
  1035. ARGBEGIN{
  1036. default:
  1037. return cliError(usage);
  1038. }ARGEND
  1039. if(argc == 0)
  1040. return cliError(usage);
  1041. vtRLock(fsys->fs->elk);
  1042. for(i=0; i<argc; i++){
  1043. if((f = fileOpen(fsys->fs, argv[i])) == nil){
  1044. consPrint("%s: %R\n", argv[i]);
  1045. continue;
  1046. }
  1047. if(!fileGetDir(f, &de)){
  1048. consPrint("%s: %R\n", argv[i]);
  1049. fileDecRef(f);
  1050. continue;
  1051. }
  1052. fsysPrintStat("\t", argv[i], &de);
  1053. deCleanup(&de);
  1054. fileDecRef(f);
  1055. }
  1056. vtRUnlock(fsys->fs->elk);
  1057. return 1;
  1058. }
  1059. static int
  1060. fsysWstat(Fsys *fsys, int argc, char* argv[])
  1061. {
  1062. File *f;
  1063. char *p;
  1064. DirEntry de;
  1065. char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n"
  1066. "\tuse - for any field to mean don't change";
  1067. ARGBEGIN{
  1068. default:
  1069. return cliError(usage);
  1070. }ARGEND
  1071. if(argc != 6)
  1072. return cliError(usage);
  1073. vtRLock(fsys->fs->elk);
  1074. if((f = fileOpen(fsys->fs, argv[0])) == nil){
  1075. vtSetError("console wstat - walk - %R");
  1076. vtRUnlock(fsys->fs->elk);
  1077. return 0;
  1078. }
  1079. if(!fileGetDir(f, &de)){
  1080. vtSetError("console wstat - stat - %R");
  1081. fileDecRef(f);
  1082. vtRUnlock(fsys->fs->elk);
  1083. return 0;
  1084. }
  1085. fsysPrintStat("\told: w", argv[0], &de);
  1086. if(strcmp(argv[1], "-") != 0){
  1087. if(!validFileName(argv[1])){
  1088. vtSetError("console wstat - bad elem");
  1089. goto error;
  1090. }
  1091. vtMemFree(de.elem);
  1092. de.elem = vtStrDup(argv[1]);
  1093. }
  1094. if(strcmp(argv[2], "-") != 0){
  1095. if(!validUserName(argv[2])){
  1096. vtSetError("console wstat - bad uid");
  1097. goto error;
  1098. }
  1099. vtMemFree(de.uid);
  1100. de.uid = vtStrDup(argv[2]);
  1101. }
  1102. if(strcmp(argv[3], "-") != 0){
  1103. if(!validUserName(argv[3])){
  1104. vtSetError("console wstat - bad gid");
  1105. goto error;
  1106. }
  1107. vtMemFree(de.gid);
  1108. de.gid = vtStrDup(argv[3]);
  1109. }
  1110. if(strcmp(argv[4], "-") != 0){
  1111. if(!fsysParseMode(argv[4], &de.mode)){
  1112. vtSetError("console wstat - bad mode");
  1113. goto error;
  1114. }
  1115. }
  1116. if(strcmp(argv[5], "-") != 0){
  1117. de.size = strtoull(argv[5], &p, 0);
  1118. if(argv[5][0] == '\0' || *p != '\0' || (int64_t)de.size < 0){
  1119. vtSetError("console wstat - bad length");
  1120. goto error;
  1121. }
  1122. }
  1123. if(!fileSetDir(f, &de, uidadm)){
  1124. vtSetError("console wstat - %R");
  1125. goto error;
  1126. }
  1127. deCleanup(&de);
  1128. if(!fileGetDir(f, &de)){
  1129. vtSetError("console wstat - stat2 - %R");
  1130. goto error;
  1131. }
  1132. fsysPrintStat("\tnew: w", argv[0], &de);
  1133. deCleanup(&de);
  1134. fileDecRef(f);
  1135. vtRUnlock(fsys->fs->elk);
  1136. return 1;
  1137. error:
  1138. deCleanup(&de); /* okay to do this twice */
  1139. fileDecRef(f);
  1140. vtRUnlock(fsys->fs->elk);
  1141. return 0;
  1142. }
  1143. static void
  1144. fsckClri(Fsck *fsck, char *name, MetaBlock *mb, int i, Block *b)
  1145. {
  1146. USED(name);
  1147. if((fsck->flags&DoClri) == 0)
  1148. return;
  1149. mbDelete(mb, i);
  1150. mbPack(mb);
  1151. blockDirty(b);
  1152. }
  1153. static void
  1154. fsckClose(Fsck *fsck, Block *b, uint32_t epoch)
  1155. {
  1156. Label l;
  1157. if((fsck->flags&DoClose) == 0)
  1158. return;
  1159. l = b->l;
  1160. if(l.state == BsFree || (l.state&BsClosed)){
  1161. consPrint("%#ux is already closed\n", b->addr);
  1162. return;
  1163. }
  1164. if(epoch){
  1165. l.state |= BsClosed;
  1166. l.epochClose = epoch;
  1167. }else
  1168. l.state = BsFree;
  1169. if(!blockSetLabel(b, &l, 0))
  1170. consPrint("%#ux setlabel: %R\n", b->addr);
  1171. }
  1172. static void
  1173. fsckClre(Fsck *fsck, Block *b, int offset)
  1174. {
  1175. Entry e;
  1176. if((fsck->flags&DoClre) == 0)
  1177. return;
  1178. if(offset<0 || offset*VtEntrySize >= fsck->bsize){
  1179. consPrint("bad clre\n");
  1180. return;
  1181. }
  1182. memset(&e, 0, sizeof e);
  1183. entryPack(&e, b->data, offset);
  1184. blockDirty(b);
  1185. }
  1186. static void
  1187. fsckClrp(Fsck *fsck, Block *b, int offset)
  1188. {
  1189. if((fsck->flags&DoClrp) == 0)
  1190. return;
  1191. if(offset<0 || offset*VtScoreSize >= fsck->bsize){
  1192. consPrint("bad clre\n");
  1193. return;
  1194. }
  1195. memmove(b->data+offset*VtScoreSize, vtZeroScore, VtScoreSize);
  1196. blockDirty(b);
  1197. }
  1198. static int
  1199. fsysCheck(Fsys *fsys, int argc, char *argv[])
  1200. {
  1201. int i, halting;
  1202. char *usage = "usage: [fsys name] check [-v] [options]";
  1203. Fsck fsck;
  1204. Block *b;
  1205. Super super;
  1206. memset(&fsck, 0, sizeof fsck);
  1207. fsck.fs = fsys->fs;
  1208. fsck.clri = fsckClri;
  1209. fsck.clre = fsckClre;
  1210. fsck.clrp = fsckClrp;
  1211. fsck.close = fsckClose;
  1212. fsck.print = consPrint;
  1213. ARGBEGIN{
  1214. default:
  1215. return cliError(usage);
  1216. }ARGEND
  1217. for(i=0; i<argc; i++){
  1218. if(strcmp(argv[i], "pblock") == 0)
  1219. fsck.printblocks = 1;
  1220. else if(strcmp(argv[i], "pdir") == 0)
  1221. fsck.printdirs = 1;
  1222. else if(strcmp(argv[i], "pfile") == 0)
  1223. fsck.printfiles = 1;
  1224. else if(strcmp(argv[i], "bclose") == 0)
  1225. fsck.flags |= DoClose;
  1226. else if(strcmp(argv[i], "clri") == 0)
  1227. fsck.flags |= DoClri;
  1228. else if(strcmp(argv[i], "clre") == 0)
  1229. fsck.flags |= DoClre;
  1230. else if(strcmp(argv[i], "clrp") == 0)
  1231. fsck.flags |= DoClrp;
  1232. else if(strcmp(argv[i], "fix") == 0)
  1233. fsck.flags |= DoClose|DoClri|DoClre|DoClrp;
  1234. else if(strcmp(argv[i], "venti") == 0)
  1235. fsck.useventi = 1;
  1236. else if(strcmp(argv[i], "snapshot") == 0)
  1237. fsck.walksnapshots = 1;
  1238. else{
  1239. consPrint("unknown option '%s'\n", argv[i]);
  1240. return cliError(usage);
  1241. }
  1242. }
  1243. halting = fsys->fs->halted==0;
  1244. if(halting)
  1245. fsHalt(fsys->fs);
  1246. if(fsys->fs->arch){
  1247. b = superGet(fsys->fs->cache, &super);
  1248. if(b == nil){
  1249. consPrint("could not load super block\n");
  1250. goto Out;
  1251. }
  1252. blockPut(b);
  1253. if(super.current != NilBlock){
  1254. consPrint("cannot check fs while archiver is running; "
  1255. "wait for it to finish\n");
  1256. goto Out;
  1257. }
  1258. }
  1259. fsCheck(&fsck);
  1260. consPrint("fsck: %d clri, %d clre, %d clrp, %d bclose\n",
  1261. fsck.nclri, fsck.nclre, fsck.nclrp, fsck.nclose);
  1262. Out:
  1263. if(halting)
  1264. fsUnhalt(fsys->fs);
  1265. return 1;
  1266. }
  1267. static int
  1268. fsysVenti(char* name, int argc, char* argv[])
  1269. {
  1270. int r;
  1271. char *host;
  1272. char *usage = "usage: [fsys name] venti [address]";
  1273. Fsys *fsys;
  1274. ARGBEGIN{
  1275. default:
  1276. return cliError(usage);
  1277. }ARGEND
  1278. if(argc == 0)
  1279. host = nil;
  1280. else if(argc == 1)
  1281. host = argv[0];
  1282. else
  1283. return cliError(usage);
  1284. if((fsys = _fsysGet(name)) == nil)
  1285. return 0;
  1286. vtLock(fsys->lock);
  1287. if(host == nil)
  1288. host = fsys->venti;
  1289. else{
  1290. vtMemFree(fsys->venti);
  1291. if(host[0])
  1292. fsys->venti = vtStrDup(host);
  1293. else{
  1294. host = nil;
  1295. fsys->venti = nil;
  1296. }
  1297. }
  1298. /* already open: do a redial */
  1299. if(fsys->fs != nil){
  1300. if(fsys->session == nil){
  1301. vtSetError("file system was opened with -V");
  1302. r = 0;
  1303. goto out;
  1304. }
  1305. r = 1;
  1306. if(!myRedial(fsys->session, host)
  1307. || !vtConnect(fsys->session, 0))
  1308. r = 0;
  1309. goto out;
  1310. }
  1311. /* not yet open: try to dial */
  1312. if(fsys->session)
  1313. vtClose(fsys->session);
  1314. r = 1;
  1315. if((fsys->session = myDial(host, 0)) == nil
  1316. || !vtConnect(fsys->session, 0))
  1317. r = 0;
  1318. out:
  1319. vtUnlock(fsys->lock);
  1320. fsysPut(fsys);
  1321. return r;
  1322. }
  1323. static uint32_t
  1324. freemem(void)
  1325. {
  1326. int nf, pgsize = 0;
  1327. uint64_t size, userpgs = 0, userused = 0;
  1328. char *ln, *sl;
  1329. char *fields[2];
  1330. Biobuf *bp;
  1331. size = 64*1024*1024;
  1332. bp = Bopen("#c/swap", OREAD);
  1333. if (bp != nil) {
  1334. while ((ln = Brdline(bp, '\n')) != nil) {
  1335. ln[Blinelen(bp)-1] = '\0';
  1336. nf = tokenize(ln, fields, nelem(fields));
  1337. if (nf != 2)
  1338. continue;
  1339. if (strcmp(fields[1], "pagesize") == 0)
  1340. pgsize = atoi(fields[0]);
  1341. else if (strcmp(fields[1], "user") == 0) {
  1342. sl = strchr(fields[0], '/');
  1343. if (sl == nil)
  1344. continue;
  1345. userpgs = atoll(sl+1);
  1346. userused = atoll(fields[0]);
  1347. }
  1348. }
  1349. Bterm(bp);
  1350. if (pgsize > 0 && userpgs > 0)
  1351. size = (userpgs - userused) * pgsize;
  1352. }
  1353. /* cap it to keep the size within 32 bits */
  1354. if (size >= 3840UL * 1024 * 1024)
  1355. size = 3840UL * 1024 * 1024;
  1356. return size;
  1357. }
  1358. static int
  1359. fsysOpen(char* name, int argc, char* argv[])
  1360. {
  1361. char *p, *host;
  1362. Fsys *fsys;
  1363. int noauth, noventi, noperm, rflag, wstatallow, noatimeupd;
  1364. int32_t ncache;
  1365. char *usage = "usage: fsys name open [-APVWr] [-c ncache]";
  1366. ncache = 1000;
  1367. noauth = noperm = wstatallow = noventi = noatimeupd = 0;
  1368. rflag = OReadWrite;
  1369. ARGBEGIN{
  1370. default:
  1371. return cliError(usage);
  1372. case 'A':
  1373. noauth = 1;
  1374. break;
  1375. case 'P':
  1376. noperm = 1;
  1377. break;
  1378. case 'V':
  1379. noventi = 1;
  1380. break;
  1381. case 'W':
  1382. wstatallow = 1;
  1383. break;
  1384. case 'a':
  1385. noatimeupd = 1;
  1386. break;
  1387. case 'c':
  1388. p = ARGF();
  1389. if(p == nil)
  1390. return cliError(usage);
  1391. ncache = strtol(argv[0], &p, 0);
  1392. if(ncache <= 0 || p == argv[0] || *p != '\0')
  1393. return cliError(usage);
  1394. break;
  1395. case 'r':
  1396. rflag = OReadOnly;
  1397. break;
  1398. }ARGEND
  1399. if(argc)
  1400. return cliError(usage);
  1401. if((fsys = _fsysGet(name)) == nil)
  1402. return 0;
  1403. /* automatic memory sizing? */
  1404. if(mempcnt > 0) {
  1405. /* TODO: 8K is a hack; use the actual block size */
  1406. ncache = (((int64_t)freemem() * mempcnt) / 100) / (8*1024);
  1407. if (ncache < 100)
  1408. ncache = 100;
  1409. }
  1410. vtLock(fsys->lock);
  1411. if(fsys->fs != nil){
  1412. vtSetError(EFsysBusy, fsys->name);
  1413. vtUnlock(fsys->lock);
  1414. fsysPut(fsys);
  1415. return 0;
  1416. }
  1417. if(noventi){
  1418. if(fsys->session){
  1419. vtClose(fsys->session);
  1420. fsys->session = nil;
  1421. }
  1422. }
  1423. else if(fsys->session == nil){
  1424. if(fsys->venti && fsys->venti[0])
  1425. host = fsys->venti;
  1426. else
  1427. host = nil;
  1428. fsys->session = myDial(host, 1);
  1429. if(!vtConnect(fsys->session, nil) && !noventi)
  1430. fprint(2, "warning: connecting to venti: %R\n");
  1431. }
  1432. if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){
  1433. vtSetError("fsOpen: %R");
  1434. vtUnlock(fsys->lock);
  1435. fsysPut(fsys);
  1436. return 0;
  1437. }
  1438. fsys->fs->name = fsys->name; /* for better error messages */
  1439. fsys->noauth = noauth;
  1440. fsys->noperm = noperm;
  1441. fsys->wstatallow = wstatallow;
  1442. fsys->fs->noatimeupd = noatimeupd;
  1443. vtUnlock(fsys->lock);
  1444. fsysPut(fsys);
  1445. if(strcmp(name, "main") == 0)
  1446. usersFileRead(nil);
  1447. return 1;
  1448. }
  1449. static int
  1450. fsysUnconfig(char* name, int argc, char* argv[])
  1451. {
  1452. Fsys *fsys, **fp;
  1453. char *usage = "usage: fsys name unconfig";
  1454. ARGBEGIN{
  1455. default:
  1456. return cliError(usage);
  1457. }ARGEND
  1458. if(argc)
  1459. return cliError(usage);
  1460. vtLock(sbox.lock);
  1461. fp = &sbox.head;
  1462. for(fsys = *fp; fsys != nil; fsys = fsys->next){
  1463. if(strcmp(fsys->name, name) == 0)
  1464. break;
  1465. fp = &fsys->next;
  1466. }
  1467. if(fsys == nil){
  1468. vtSetError(EFsysNotFound, name);
  1469. vtUnlock(sbox.lock);
  1470. return 0;
  1471. }
  1472. if(fsys->ref != 0 || fsys->fs != nil){
  1473. vtSetError(EFsysBusy, fsys->name);
  1474. vtUnlock(sbox.lock);
  1475. return 0;
  1476. }
  1477. *fp = fsys->next;
  1478. vtUnlock(sbox.lock);
  1479. if(fsys->session != nil){
  1480. vtClose(fsys->session);
  1481. vtFree(fsys->session);
  1482. }
  1483. if(fsys->venti != nil)
  1484. vtMemFree(fsys->venti);
  1485. if(fsys->dev != nil)
  1486. vtMemFree(fsys->dev);
  1487. if(fsys->name != nil)
  1488. vtMemFree(fsys->name);
  1489. vtMemFree(fsys);
  1490. return 1;
  1491. }
  1492. static int
  1493. fsysConfig(char* name, int argc, char* argv[])
  1494. {
  1495. Fsys *fsys;
  1496. char *part;
  1497. char *usage = "usage: fsys name config [dev]";
  1498. ARGBEGIN{
  1499. default:
  1500. return cliError(usage);
  1501. }ARGEND
  1502. if(argc > 1)
  1503. return cliError(usage);
  1504. if(argc == 0)
  1505. part = foptname;
  1506. else
  1507. part = argv[0];
  1508. if((fsys = _fsysGet(part)) != nil){
  1509. vtLock(fsys->lock);
  1510. if(fsys->fs != nil){
  1511. vtSetError(EFsysBusy, fsys->name);
  1512. vtUnlock(fsys->lock);
  1513. fsysPut(fsys);
  1514. return 0;
  1515. }
  1516. vtMemFree(fsys->dev);
  1517. fsys->dev = vtStrDup(part);
  1518. vtUnlock(fsys->lock);
  1519. }
  1520. else if((fsys = fsysAlloc(name, part)) == nil)
  1521. return 0;
  1522. fsysPut(fsys);
  1523. return 1;
  1524. }
  1525. static struct {
  1526. char* cmd;
  1527. int (*f)(Fsys*, int, char**);
  1528. int (*f1)(char*, int, char**);
  1529. } fsyscmd[] = {
  1530. { "close", fsysClose, },
  1531. { "config", nil, fsysConfig, },
  1532. { "open", nil, fsysOpen, },
  1533. { "unconfig", nil, fsysUnconfig, },
  1534. { "venti", nil, fsysVenti, },
  1535. { "bfree", fsysBfree, },
  1536. { "block", fsysBlock, },
  1537. { "check", fsysCheck, },
  1538. { "clre", fsysClre, },
  1539. { "clri", fsysClri, },
  1540. { "clrp", fsysClrp, },
  1541. { "create", fsysCreate, },
  1542. { "df", fsysDf, },
  1543. { "epoch", fsysEpoch, },
  1544. { "halt", fsysHalt, },
  1545. { "label", fsysLabel, },
  1546. { "remove", fsysRemove, },
  1547. { "snap", fsysSnap, },
  1548. { "snaptime", fsysSnapTime, },
  1549. { "snapclean", fsysSnapClean, },
  1550. { "stat", fsysStat, },
  1551. { "sync", fsysSync, },
  1552. { "unhalt", fsysUnhalt, },
  1553. { "wstat", fsysWstat, },
  1554. { "vac", fsysVac, },
  1555. { nil, nil, },
  1556. };
  1557. static int
  1558. fsysXXX1(Fsys *fsys, int i, int argc, char* argv[])
  1559. {
  1560. int r;
  1561. vtLock(fsys->lock);
  1562. if(fsys->fs == nil){
  1563. vtUnlock(fsys->lock);
  1564. vtSetError(EFsysNotOpen, fsys->name);
  1565. return 0;
  1566. }
  1567. if(fsys->fs->halted
  1568. && fsyscmd[i].f != fsysUnhalt && fsyscmd[i].f != fsysCheck){
  1569. vtSetError("file system %s is halted", fsys->name);
  1570. vtUnlock(fsys->lock);
  1571. return 0;
  1572. }
  1573. r = (*fsyscmd[i].f)(fsys, argc, argv);
  1574. vtUnlock(fsys->lock);
  1575. return r;
  1576. }
  1577. static int
  1578. fsysXXX(char* name, int argc, char* argv[])
  1579. {
  1580. int i, r;
  1581. Fsys *fsys;
  1582. for(i = 0; fsyscmd[i].cmd != nil; i++){
  1583. if(strcmp(fsyscmd[i].cmd, argv[0]) == 0)
  1584. break;
  1585. }
  1586. if(fsyscmd[i].cmd == nil){
  1587. vtSetError("unknown command - '%s'", argv[0]);
  1588. return 0;
  1589. }
  1590. /* some commands want the name... */
  1591. if(fsyscmd[i].f1 != nil){
  1592. if(strcmp(name, FsysAll) == 0){
  1593. vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]);
  1594. return 0;
  1595. }
  1596. return (*fsyscmd[i].f1)(name, argc, argv);
  1597. }
  1598. /* ... but most commands want the Fsys */
  1599. if(strcmp(name, FsysAll) == 0){
  1600. r = 1;
  1601. vtRLock(sbox.lock);
  1602. for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
  1603. fsys->ref++;
  1604. r = fsysXXX1(fsys, i, argc, argv) && r;
  1605. fsys->ref--;
  1606. }
  1607. vtRUnlock(sbox.lock);
  1608. }else{
  1609. if((fsys = _fsysGet(name)) == nil)
  1610. return 0;
  1611. r = fsysXXX1(fsys, i, argc, argv);
  1612. fsysPut(fsys);
  1613. }
  1614. return r;
  1615. }
  1616. static int
  1617. cmdFsysXXX(int argc, char* argv[])
  1618. {
  1619. char *name;
  1620. if((name = sbox.curfsys) == nil){
  1621. vtSetError(EFsysNoCurrent, argv[0]);
  1622. return 0;
  1623. }
  1624. return fsysXXX(name, argc, argv);
  1625. }
  1626. static int
  1627. cmdFsys(int argc, char* argv[])
  1628. {
  1629. Fsys *fsys;
  1630. char *usage = "usage: fsys [name ...]";
  1631. ARGBEGIN{
  1632. default:
  1633. return cliError(usage);
  1634. }ARGEND
  1635. if(argc == 0){
  1636. vtRLock(sbox.lock);
  1637. currfsysname = sbox.head->name;
  1638. for(fsys = sbox.head; fsys != nil; fsys = fsys->next)
  1639. consPrint("\t%s\n", fsys->name);
  1640. vtRUnlock(sbox.lock);
  1641. return 1;
  1642. }
  1643. if(argc == 1){
  1644. fsys = nil;
  1645. if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil)
  1646. return 0;
  1647. sbox.curfsys = vtStrDup(argv[0]);
  1648. consPrompt(sbox.curfsys);
  1649. if(fsys)
  1650. fsysPut(fsys);
  1651. return 1;
  1652. }
  1653. return fsysXXX(argv[0], argc-1, argv+1);
  1654. }
  1655. int
  1656. fsysInit(void)
  1657. {
  1658. int i;
  1659. fmtinstall('H', encodefmt);
  1660. fmtinstall('V', scoreFmt);
  1661. fmtinstall('R', vtErrFmt);
  1662. fmtinstall('L', labelFmt);
  1663. sbox.lock = vtLockAlloc();
  1664. cliAddCmd("fsys", cmdFsys);
  1665. for(i = 0; fsyscmd[i].cmd != nil; i++){
  1666. if(fsyscmd[i].f != nil)
  1667. cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX);
  1668. }
  1669. /* the venti cmd is special: the fs can be either open or closed */
  1670. cliAddCmd("venti", cmdFsysXXX);
  1671. cliAddCmd("printconfig", cmdPrintConfig);
  1672. return 1;
  1673. }