conf.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "fs.h"
  8. /*
  9. * Where configuration info is left for the loaded programme.
  10. * This will turn into a structure as more is done by the boot loader
  11. * (e.g. why parse the .ini file twice?).
  12. * There are 3584 bytes available at CONFADDR.
  13. *
  14. * The low-level boot routines in l.s leave data for us at CONFADDR,
  15. * which we pick up before reading the plan9.ini file.
  16. */
  17. #define BOOTLINELEN 64
  18. #define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
  19. #define BOOTARGSLEN (3584-0x200-BOOTLINELEN)
  20. #define MAXCONF 100
  21. static char *confname[MAXCONF];
  22. static char *confval[MAXCONF];
  23. static int nconf;
  24. extern char **ini;
  25. typedef struct {
  26. char* name;
  27. int start;
  28. int end;
  29. } Mblock;
  30. typedef struct {
  31. char* tag;
  32. Mblock* mb;
  33. } Mitem;
  34. static Mblock mblock[MAXCONF];
  35. static int nmblock;
  36. static Mitem mitem[MAXCONF];
  37. static int nmitem;
  38. static char* mdefault;
  39. static char mdefaultbuf[10];
  40. static int mtimeout;
  41. static char*
  42. comma(char* line, char** residue)
  43. {
  44. char *q, *r;
  45. if((q = strchr(line, ',')) != nil){
  46. *q++ = 0;
  47. if(*q == ' ')
  48. q++;
  49. }
  50. *residue = q;
  51. if((r = strchr(line, ' ')) != nil)
  52. *r = 0;
  53. if(*line == ' ')
  54. line++;
  55. return line;
  56. }
  57. static Mblock*
  58. findblock(char* name, char** residue)
  59. {
  60. int i;
  61. char *p;
  62. p = comma(name, residue);
  63. for(i = 0; i < nmblock; i++){
  64. if(strcmp(p, mblock[i].name) == 0)
  65. return &mblock[i];
  66. }
  67. return nil;
  68. }
  69. static Mitem*
  70. finditem(char* name, char** residue)
  71. {
  72. int i;
  73. char *p;
  74. p = comma(name, residue);
  75. for(i = 0; i < nmitem; i++){
  76. if(strcmp(p, mitem[i].mb->name) == 0)
  77. return &mitem[i];
  78. }
  79. return nil;
  80. }
  81. static void
  82. parsemenu(char* str, char* scratch, int len)
  83. {
  84. Mitem *mi;
  85. Mblock *mb, *menu;
  86. char buf[20], *p, *q, *line[MAXCONF];
  87. int i, inblock, n, show;
  88. inblock = 0;
  89. menu = nil;
  90. memmove(scratch, str, len);
  91. n = getfields(scratch, line, MAXCONF, '\n');
  92. if(n >= MAXCONF)
  93. print("warning: possibly too many lines in plan9.ini\n");
  94. for(i = 0; i < n; i++){
  95. p = line[i];
  96. if(inblock && *p == '['){
  97. mblock[nmblock].end = i;
  98. if(strcmp(mblock[nmblock].name, "menu") == 0)
  99. menu = &mblock[nmblock];
  100. nmblock++;
  101. inblock = 0;
  102. }
  103. if(*p == '['){
  104. if(nmblock == 0 && i != 0){
  105. mblock[nmblock].name = "common";
  106. mblock[nmblock].start = 0;
  107. mblock[nmblock].end = i;
  108. nmblock++;
  109. }
  110. q = strchr(p+1, ']');
  111. if(q == nil || *(q+1) != 0){
  112. print("malformed menu block header - %s\n", p);
  113. return;
  114. }
  115. *q = 0;
  116. mblock[nmblock].name = p+1;
  117. mblock[nmblock].start = i+1;
  118. inblock = 1;
  119. }
  120. }
  121. if(inblock){
  122. mblock[nmblock].end = i;
  123. nmblock++;
  124. }
  125. if(menu == nil)
  126. return;
  127. if(nmblock < 2){
  128. print("incomplete menu specification\n");
  129. return;
  130. }
  131. for(i = menu->start; i < menu->end; i++){
  132. p = line[i];
  133. if(cistrncmp(p, "menuitem=", 9) == 0){
  134. p += 9;
  135. if((mb = findblock(p, &q)) == nil){
  136. print("no block for menuitem %s\n", p);
  137. return;
  138. }
  139. if(q != nil)
  140. mitem[nmitem].tag = q;
  141. else
  142. mitem[nmitem].tag = mb->name;
  143. mitem[nmitem].mb = mb;
  144. nmitem++;
  145. }
  146. else if(cistrncmp(p, "menudefault=", 12) == 0){
  147. p += 12;
  148. if((mi = finditem(p, &q)) == nil){
  149. print("no item for menudefault %s\n", p);
  150. return;
  151. }
  152. if(q != nil)
  153. mtimeout = strtol(q, 0, 0);
  154. sprint(mdefaultbuf, "%ld", mi-mitem+1);
  155. mdefault = mdefaultbuf;
  156. }
  157. else if(cistrncmp(p, "menuconsole=", 12) == 0){
  158. p += 12;
  159. p = comma(p, &q);
  160. consinit(p, q);
  161. }
  162. else{
  163. print("invalid line in [menu] block - %s\n", p);
  164. return;
  165. }
  166. }
  167. again:
  168. print("\nPlan 9 Startup Menu:\n====================\n");
  169. for(i = 0; i < nmitem; i++)
  170. print(" %d. %s\n", i+1, mitem[i].tag);
  171. for(;;){
  172. getstr("Selection", buf, sizeof(buf), mdefault, mtimeout);
  173. mtimeout = 0;
  174. i = strtol(buf, &p, 0)-1;
  175. if(i < 0 || i >= nmitem)
  176. goto again;
  177. switch(*p){
  178. case 'p':
  179. case 'P':
  180. show = 1;
  181. print("\n");
  182. break;
  183. case 0:
  184. show = 0;
  185. break;
  186. default:
  187. continue;
  188. }
  189. mi = &mitem[i];
  190. p = str;
  191. p += sprint(p, "menuitem=%s\n", mi->mb->name);
  192. for(i = 0; i < nmblock; i++){
  193. mb = &mblock[i];
  194. if(mi->mb != mb && cistrcmp(mb->name, "common") != 0)
  195. continue;
  196. for(n = mb->start; n < mb->end; n++)
  197. p += sprint(p, "%s\n", line[n]);
  198. }
  199. if(show){
  200. for(q = str; q < p; q += i){
  201. if((i = print(q)) <= 0)
  202. break;
  203. }
  204. goto again;
  205. }
  206. break;
  207. }
  208. print("\n");
  209. }
  210. /*
  211. static void
  212. msleep(int msec)
  213. {
  214. ulong start;
  215. for(start = m->ticks; TK2MS(m->ticks - start) < msec; )
  216. ;
  217. }
  218. */
  219. void
  220. readlsconf(void)
  221. {
  222. uchar *p;
  223. p = (uchar*)CONFADDR;
  224. for(;;) {
  225. if(strcmp((char*)p, "APM") == 0){
  226. apm.haveinfo = 1;
  227. apm.ax = *(ushort*)(p+4);
  228. apm.cx = *(ushort*)(p+6);
  229. apm.dx = *(ushort*)(p+8);
  230. apm.di = *(ushort*)(p+10);
  231. apm.ebx = *(ulong*)(p+12);
  232. apm.esi = *(ulong*)(p+16);
  233. print("apm ax=%x cx=%x dx=%x di=%x ebx=%x esi=%x\n",
  234. apm.ax, apm.cx, apm.dx, apm.di, apm.ebx, apm.esi);
  235. p += 20;
  236. continue;
  237. }
  238. break;
  239. }
  240. }
  241. char*
  242. getconf(char *name)
  243. {
  244. int i, n, nmatch;
  245. char buf[20];
  246. nmatch = 0;
  247. for(i = 0; i < nconf; i++)
  248. if(cistrcmp(confname[i], name) == 0)
  249. nmatch++;
  250. switch(nmatch) {
  251. default:
  252. print("\n");
  253. nmatch = 0;
  254. for(i = 0; i < nconf; i++)
  255. if(cistrcmp(confname[i], name) == 0)
  256. print("%d. %s\n", ++nmatch, confval[i]);
  257. print("%d. none of the above\n", ++nmatch);
  258. do {
  259. getstr(name, buf, sizeof(buf), nil, 0);
  260. n = atoi(buf);
  261. } while(n < 1 || n > nmatch);
  262. for(i = 0; i < nconf; i++)
  263. if(cistrcmp(confname[i], name) == 0)
  264. if(--n == 0)
  265. return confval[i];
  266. break;
  267. case 1:
  268. for(i = 0; i < nconf; i++)
  269. if(cistrcmp(confname[i], name) == 0)
  270. return confval[i];
  271. break;
  272. case 0:
  273. break;
  274. }
  275. return nil;
  276. }
  277. void
  278. addconf(char *fmt, ...)
  279. {
  280. va_list arg;
  281. va_start(arg, fmt);
  282. vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg);
  283. va_end(arg);
  284. }
  285. void
  286. changeconf(char *fmt, ...)
  287. {
  288. va_list arg;
  289. char *p, *q, pref[20], buf[128];
  290. va_start(arg, fmt);
  291. vseprint(buf, buf+sizeof buf, fmt, arg);
  292. va_end(arg);
  293. pref[0] = '\n';
  294. strncpy(pref+1, buf, 19);
  295. pref[19] = '\0';
  296. if(p = strchr(pref, '='))
  297. *(p+1) = '\0';
  298. else
  299. print("warning: did not change %s in plan9.ini\n", buf);
  300. /* find old line by looking for \nwhat= */
  301. if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0)
  302. p = BOOTARGS;
  303. else if(p = strstr(BOOTARGS, pref))
  304. p++;
  305. else
  306. p = nil;
  307. /* move rest of args up, deleting what= line. */
  308. if(p != nil && (q = strchr(p, '\n')) != nil)
  309. memmove(p, q+1, strlen(q+1)+1);
  310. /* add replacement to end */
  311. addconf("%s", buf);
  312. }
  313. /*
  314. * read configuration file
  315. */
  316. static char inibuf[BOOTARGSLEN];
  317. static char id[8] = "ZORT 0\r\n";
  318. int
  319. dotini(Fs *fs)
  320. {
  321. File rc;
  322. int blankline, i, incomment, inspace, n;
  323. char *cp, *p, *q, *line[MAXCONF];
  324. if(fswalk(fs, *ini, &rc) <= 0)
  325. return -1;
  326. cp = inibuf;
  327. *cp = 0;
  328. n = fsread(&rc, cp, BOOTARGSLEN-1);
  329. if(n <= 0)
  330. return -1;
  331. cp[n] = 0;
  332. /*
  333. * Strip out '\r', change '\t' -> ' '.
  334. * Change runs of spaces into single spaces.
  335. * Strip out trailing spaces, blank lines.
  336. *
  337. * We do this before we make the copy so that if we
  338. * need to change the copy, it is already fairly clean.
  339. * The main need is in the case when plan9.ini has been
  340. * padded with lots of trailing spaces, as is the case
  341. * for those created during a distribution install.
  342. */
  343. p = cp;
  344. blankline = 1;
  345. incomment = inspace = 0;
  346. for(q = cp; *q; q++){
  347. if(*q == '\r')
  348. continue;
  349. if(*q == '\t')
  350. *q = ' ';
  351. if(*q == ' '){
  352. inspace = 1;
  353. continue;
  354. }
  355. if(*q == '\n'){
  356. if(!blankline){
  357. if(!incomment)
  358. *p++ = '\n';
  359. blankline = 1;
  360. }
  361. incomment = inspace = 0;
  362. continue;
  363. }
  364. if(inspace){
  365. if(!blankline && !incomment)
  366. *p++ = ' ';
  367. inspace = 0;
  368. }
  369. if(blankline && *q == '#')
  370. incomment = 1;
  371. blankline = 0;
  372. if(!incomment)
  373. *p++ = *q;
  374. }
  375. if(p > cp && p[-1] != '\n')
  376. *p++ = '\n';
  377. *p++ = 0;
  378. n = p-cp;
  379. parsemenu(cp, BOOTARGS, n);
  380. /*
  381. * Keep a copy.
  382. * We could change this to pass the parsed strings
  383. * to the booted programme instead of the raw
  384. * string, then it only gets done once.
  385. */
  386. if(strncmp(cp, id, sizeof(id))){
  387. memmove(BOOTARGS, id, sizeof(id));
  388. if(n+1+sizeof(id) >= BOOTARGSLEN)
  389. n -= sizeof(id);
  390. memmove(BOOTARGS+sizeof(id), cp, n+1);
  391. }
  392. else
  393. memmove(BOOTARGS, cp, n+1);
  394. n = getfields(cp, line, MAXCONF, '\n');
  395. for(i = 0; i < n; i++){
  396. cp = strchr(line[i], '=');
  397. if(cp == 0)
  398. continue;
  399. *cp++ = 0;
  400. if(cp - line[i] >= NAMELEN+1)
  401. *(line[i]+NAMELEN-1) = 0;
  402. confname[nconf] = line[i];
  403. confval[nconf] = cp;
  404. nconf++;
  405. }
  406. return 0;
  407. }
  408. static int
  409. parseether(uchar *to, char *from)
  410. {
  411. char nip[4];
  412. char *p;
  413. int i;
  414. p = from;
  415. while(*p == ' ')
  416. ++p;
  417. for(i = 0; i < 6; i++){
  418. if(*p == 0)
  419. return -1;
  420. nip[0] = *p++;
  421. if(*p == 0)
  422. return -1;
  423. nip[1] = *p++;
  424. nip[2] = 0;
  425. to[i] = strtoul(nip, 0, 16);
  426. if(*p == ':')
  427. p++;
  428. }
  429. return 0;
  430. }
  431. int
  432. isaconfig(char *class, int ctlrno, ISAConf *isa)
  433. {
  434. char cc[NAMELEN], *p, *q, *r;
  435. int n;
  436. sprint(cc, "%s%d", class, ctlrno);
  437. for(n = 0; n < nconf; n++){
  438. if(cistrncmp(confname[n], cc, NAMELEN))
  439. continue;
  440. isa->nopt = 0;
  441. p = confval[n];
  442. while(*p){
  443. while(*p == ' ' || *p == '\t')
  444. p++;
  445. if(*p == '\0')
  446. break;
  447. if(cistrncmp(p, "type=", 5) == 0){
  448. p += 5;
  449. for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
  450. if(*p == '\0' || *p == ' ' || *p == '\t')
  451. break;
  452. *q = *p++;
  453. }
  454. *q = '\0';
  455. }
  456. else if(cistrncmp(p, "port=", 5) == 0)
  457. isa->port = strtoul(p+5, &p, 0);
  458. else if(cistrncmp(p, "irq=", 4) == 0)
  459. isa->irq = strtoul(p+4, &p, 0);
  460. else if(cistrncmp(p, "mem=", 4) == 0)
  461. isa->mem = strtoul(p+4, &p, 0);
  462. else if(cistrncmp(p, "size=", 5) == 0)
  463. isa->size = strtoul(p+5, &p, 0);
  464. else if(cistrncmp(p, "ea=", 3) == 0){
  465. if(parseether(isa->ea, p+3) == -1)
  466. memset(isa->ea, 0, 6);
  467. }
  468. else if(isa->nopt < NISAOPT){
  469. r = isa->opt[isa->nopt];
  470. while(*p && *p != ' ' && *p != '\t'){
  471. *r++ = *p++;
  472. if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
  473. break;
  474. }
  475. *r = '\0';
  476. isa->nopt++;
  477. }
  478. while(*p && *p != ' ' && *p != '\t')
  479. p++;
  480. }
  481. return 1;
  482. }
  483. return 0;
  484. }