conf.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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 "dosfs.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. continue;
  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. donprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, (&fmt+1));
  281. }
  282. void
  283. changeconf(char *fmt, ...)
  284. {
  285. char *p, *q, pref[20], buf[128];
  286. donprint(buf, buf+sizeof buf, fmt, (&fmt+1));
  287. strncpy(pref+1, buf, 19);
  288. pref[19] = '\0';
  289. if(p = strchr(pref, '='))
  290. *(p+1) = '\0';
  291. else
  292. print("warning: did not change %s in plan9.ini\n", buf);
  293. /* find old line by looking for \nwhat= */
  294. pref[0] = '\n';
  295. if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0)
  296. p = BOOTARGS;
  297. else if(p = strstr(BOOTARGS, pref))
  298. p++;
  299. else
  300. p = nil;
  301. /* move rest of args up, deleting what= line. */
  302. if(p != nil && (q = strchr(p, '\n')) != nil)
  303. memmove(p, q+1, strlen(q+1)+1);
  304. /* add replacement to end */
  305. addconf("%s", buf);
  306. }
  307. /*
  308. * read configuration file
  309. */
  310. static char inibuf[BOOTARGSLEN];
  311. static char id[8] = "ZORT 0\r\n";
  312. int
  313. dotini(Dos *dos)
  314. {
  315. Dosfile rc;
  316. int blankline, i, incomment, inspace, n;
  317. char *cp, *p, *q, *line[MAXCONF];
  318. if(dosstat(dos, *ini, &rc) <= 0)
  319. return -1;
  320. cp = inibuf;
  321. *cp = 0;
  322. n = dosread(&rc, cp, BOOTARGSLEN-1);
  323. if(n <= 0)
  324. return -1;
  325. cp[n] = 0;
  326. /*
  327. * Strip out '\r', change '\t' -> ' '.
  328. * Change runs of spaces into single spaces.
  329. * Strip out trailing spaces, blank lines.
  330. *
  331. * We do this before we make the copy so that if we
  332. * need to change the copy, it is already fairly clean.
  333. * The main need is in the case when plan9.ini has been
  334. * padded with lots of trailing spaces, as is the case
  335. * for those created during a distribution install.
  336. */
  337. p = cp;
  338. blankline = 1;
  339. incomment = inspace = 0;
  340. for(q = cp; *q; q++){
  341. if(*q == '\r')
  342. continue;
  343. if(*q == '\t')
  344. *q = ' ';
  345. if(*q == ' '){
  346. inspace = 1;
  347. continue;
  348. }
  349. if(*q == '\n'){
  350. if(!blankline){
  351. if(!incomment)
  352. *p++ = '\n';
  353. blankline = 1;
  354. }
  355. incomment = inspace = 0;
  356. continue;
  357. }
  358. if(inspace){
  359. if(!blankline && !incomment)
  360. *p++ = ' ';
  361. inspace = 0;
  362. }
  363. if(blankline && *q == '#')
  364. incomment = 1;
  365. blankline = 0;
  366. if(!incomment)
  367. *p++ = *q;
  368. }
  369. if(p > cp && p[-1] != '\n')
  370. *p++ = '\n';
  371. *p++ = 0;
  372. n = p-cp;
  373. parsemenu(cp, BOOTARGS, n);
  374. /*
  375. * Keep a copy.
  376. * We could change this to pass the parsed strings
  377. * to the booted programme instead of the raw
  378. * string, then it only gets done once.
  379. */
  380. if(strncmp(cp, id, sizeof(id))){
  381. memmove(BOOTARGS, id, sizeof(id));
  382. if(n+1+sizeof(id) >= BOOTARGSLEN)
  383. n -= sizeof(id);
  384. memmove(BOOTARGS+sizeof(id), cp, n+1);
  385. }
  386. else
  387. memmove(BOOTARGS, cp, n+1);
  388. n = getfields(cp, line, MAXCONF, '\n');
  389. for(i = 0; i < n; i++){
  390. cp = strchr(line[i], '=');
  391. if(cp == 0)
  392. continue;
  393. *cp++ = 0;
  394. if(cp - line[i] >= NAMELEN+1)
  395. *(line[i]+NAMELEN-1) = 0;
  396. confname[nconf] = line[i];
  397. confval[nconf] = cp;
  398. nconf++;
  399. }
  400. return 0;
  401. }
  402. static int
  403. parseether(uchar *to, char *from)
  404. {
  405. char nip[4];
  406. char *p;
  407. int i;
  408. p = from;
  409. while(*p == ' ')
  410. ++p;
  411. for(i = 0; i < 6; i++){
  412. if(*p == 0)
  413. return -1;
  414. nip[0] = *p++;
  415. if(*p == 0)
  416. return -1;
  417. nip[1] = *p++;
  418. nip[2] = 0;
  419. to[i] = strtoul(nip, 0, 16);
  420. if(*p == ':')
  421. p++;
  422. }
  423. return 0;
  424. }
  425. int
  426. isaconfig(char *class, int ctlrno, ISAConf *isa)
  427. {
  428. char cc[NAMELEN], *p, *q, *r;
  429. int n;
  430. sprint(cc, "%s%d", class, ctlrno);
  431. for(n = 0; n < nconf; n++){
  432. if(cistrncmp(confname[n], cc, NAMELEN))
  433. continue;
  434. isa->nopt = 0;
  435. p = confval[n];
  436. while(*p){
  437. while(*p == ' ' || *p == '\t')
  438. p++;
  439. if(*p == '\0')
  440. break;
  441. if(cistrncmp(p, "type=", 5) == 0){
  442. p += 5;
  443. for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
  444. if(*p == '\0' || *p == ' ' || *p == '\t')
  445. break;
  446. *q = *p++;
  447. }
  448. *q = '\0';
  449. }
  450. else if(cistrncmp(p, "port=", 5) == 0)
  451. isa->port = strtoul(p+5, &p, 0);
  452. else if(cistrncmp(p, "irq=", 4) == 0)
  453. isa->irq = strtoul(p+4, &p, 0);
  454. else if(cistrncmp(p, "mem=", 4) == 0)
  455. isa->mem = strtoul(p+4, &p, 0);
  456. else if(cistrncmp(p, "size=", 5) == 0)
  457. isa->size = strtoul(p+5, &p, 0);
  458. else if(cistrncmp(p, "ea=", 3) == 0){
  459. if(parseether(isa->ea, p+3) == -1)
  460. memset(isa->ea, 0, 6);
  461. }
  462. else if(isa->nopt < NISAOPT){
  463. r = isa->opt[isa->nopt];
  464. while(*p && *p != ' ' && *p != '\t'){
  465. *r++ = *p++;
  466. if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
  467. break;
  468. }
  469. *r = '\0';
  470. isa->nopt++;
  471. }
  472. while(*p && *p != ' ' && *p != '\t')
  473. p++;
  474. }
  475. return 1;
  476. }
  477. return 0;
  478. }