rebootcmd.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include <a.out.h>
  8. #include "/sys/src/libmach/elf.h"
  9. enum {
  10. Ehdr32sz = 52,
  11. Phdr32sz = 32,
  12. Shdr32sz = 40,
  13. Ehdr64sz = 64,
  14. Phdr64sz = 56,
  15. Shdr64sz = 64,
  16. };
  17. static uchar elfident[] = {
  18. '\177', 'E', 'L', 'F',
  19. };
  20. void
  21. readn(Chan *c, void *vp, long n)
  22. {
  23. char *p = vp;
  24. long nn;
  25. while(n > 0) {
  26. nn = devtab[c->type]->read(c, p, n, c->offset);
  27. if(nn == 0)
  28. error(Eshort);
  29. c->offset += nn;
  30. p += nn;
  31. n -= nn;
  32. }
  33. }
  34. /* assume the elf header is in the byte order of this machine */
  35. int
  36. readelfhdr(Chan *c, ulong, Execvals *evp)
  37. {
  38. Ehdr ehdr;
  39. Phdr phdrs[3];
  40. c->offset = 0; /* back up */
  41. readn(c, &ehdr, sizeof ehdr);
  42. if(memcmp(&ehdr.ident[MAG0], elfident, sizeof elfident) != 0 ||
  43. ehdr.ident[CLASS] != ELFCLASS32)
  44. return -1;
  45. /* get textsize and datasize from Phdrs */
  46. readn(c, phdrs, sizeof phdrs);
  47. evp->entry = ehdr.elfentry;
  48. evp->textsize = phdrs[0].filesz;
  49. evp->datasize = phdrs[1].filesz;
  50. c->offset = ROUNDUP(Ehdr32sz + 3*Phdr32sz, 16); /* position for text */
  51. return 0;
  52. }
  53. static int
  54. readelf64hdr(Chan *c, ulong, Execvals *evp)
  55. {
  56. E64hdr ehdr;
  57. P64hdr phdrs[3];
  58. c->offset = 0; /* back up */
  59. readn(c, &ehdr, sizeof ehdr);
  60. if(memcmp(&ehdr.ident[MAG0], elfident, sizeof elfident) != 0 ||
  61. ehdr.ident[CLASS] != ELFCLASS64)
  62. return -1;
  63. /* get textsize and datasize from Phdrs */
  64. readn(c, phdrs, sizeof phdrs);
  65. evp->entry = ehdr.elfentry;
  66. evp->textsize = phdrs[0].filesz;
  67. evp->datasize = phdrs[1].filesz;
  68. c->offset = ROUNDUP(Ehdr64sz + 3*Phdr64sz, 16); /* position for text */
  69. return 0;
  70. }
  71. static void
  72. setbootcmd(int argc, char *argv[])
  73. {
  74. char *buf, *p, *ep;
  75. int i;
  76. buf = malloc(1024);
  77. if(buf == nil)
  78. error(Enomem);
  79. p = buf;
  80. ep = buf + 1024;
  81. for(i=0; i<argc; i++)
  82. p = seprint(p, ep, "%q ", argv[i]);
  83. *p = 0;
  84. ksetenv("bootcmd", buf, 1);
  85. free(buf);
  86. }
  87. void
  88. rebootcmd(int argc, char *argv[])
  89. {
  90. Chan *c;
  91. Exec exec;
  92. Execvals ev;
  93. ulong magic, text, rtext, entry, data, size;
  94. uchar *p;
  95. if(argc == 0)
  96. exit(0);
  97. c = namec(argv[0], Aopen, OEXEC, 0);
  98. if(waserror()){
  99. cclose(c);
  100. nexterror();
  101. }
  102. readn(c, &exec, sizeof(Exec));
  103. magic = l2be(exec.magic);
  104. /*
  105. * AOUT_MAGIC is sometimes defined like this:
  106. * #define AOUT_MAGIC V_MAGIC || magic==M_MAGIC
  107. * so we can only use it in a fairly stylized manner.
  108. */
  109. if(magic == AOUT_MAGIC) {
  110. entry = l2be(exec.entry);
  111. text = l2be(exec.text);
  112. data = l2be(exec.data);
  113. } else if(parseboothdr && (*parseboothdr)(c, magic, &ev) >= 0 ||
  114. readelfhdr(c, magic, &ev) >= 0 ||
  115. readelf64hdr(c, magic, &ev) >= 0){
  116. entry = ev.entry;
  117. text = ev.textsize;
  118. data = ev.datasize;
  119. } else {
  120. error(Ebadexec);
  121. return; /* for the compiler */
  122. }
  123. /* round text out to page boundary */
  124. rtext = ROUNDUP(entry+text, BY2PG) - entry;
  125. size = rtext + data;
  126. p = malloc(size);
  127. if(p == nil)
  128. error(Enomem);
  129. if(waserror()){
  130. free(p);
  131. nexterror();
  132. }
  133. memset(p, 0, size);
  134. readn(c, p, text);
  135. readn(c, p + rtext, data);
  136. ksetenv("bootfile", argv[0], 1);
  137. setbootcmd(argc-1, argv+1);
  138. reboot((void*)entry, p, size);
  139. panic("return from reboot!");
  140. }