/*
    KernPatch.c, Copyright 1997-1998 (c) by Lukas Ruf,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.

    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.

    For further information, please visit http://www.tik.ee.ethz.ch/~topsy

    This software is provided under the terms of the GNU General Public Licence.

    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
        This copyright notice supercedes all originally or previously used 
        copyrights being used within the source code.
        
        Author: Lukas Ruf <lr@lpr.ch>
*/

// ************************************************************************** //
// Copyrights (c) 1997 Lukas Ruf                                              //
// ************************************************************************** //
// KernPatch: Read file created by size and specified as parameter 2          //
//            Write sizes into bytes 0x02-0x0A (8Bytes) of kernel file        //
//              specified as parameter 1.                                     //
//            Text Segment is written as ".text"                              //
//            Data Segment is written as ".rodata" (GCC stores all data in it)//
// ************************************************************************** //

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MARKER "TOPSYi386"
#define SIZEOFMARK 0x10

void Hello() {
  printf("\nKernPatch: (c) by Lukas Ruf, lr@lpr.ch\n");
  printf("Program call: KernPatch <KernelFile> <KernelSizeFile>\n");
  return;
}

unsigned long GetSize(const char *pBuf, const char *pattern) {
  unsigned long xret;
  int i       = 0;
  char *xpos;
  char *xt    = new char[8];
  memset(xt   ,0,8);
  xpos  = strstr(pBuf,pattern);
  while (xpos && *xpos && (*xpos != ' ')) xpos++;   // skip .text
  while (xpos && *xpos && (*xpos == ' ')) xpos++;   // skip spaces before no.
  while (xpos && *xpos && (*xpos != ' ')) xt[i++] = *xpos++;  // get no.
  xret = (unsigned long) atol(xt);
  delete xt;
  return xret;
}

int Patch(char *pKern, char *pSize) {
  int xret    = 1;
  int fKern   = open(pKern,O_RDWR);
  int fSize   = open(pSize,O_RDONLY);
  char *bKern = new char[512];
  char *bSize = new char[512];
  char *xpos  = 0;
  int   rSize, xdo = 1;
  unsigned long *kernSize = new unsigned long;
  unsigned long *textSize = new unsigned long, *dataSize = new unsigned long;
  memset(bSize,0,512);
  memset(bKern,0,512);
  if (!((fKern != -1) &&
        (read(fKern,bKern,512) == 512) &&
        (strncmp(bKern,MARKER,strlen(MARKER)) == 0))) {
    printf(" !!!! NO VALID >TOPSYi386< KERNEL !!!!\n");
    xdo = 0;
  }
  if (xdo) {
    printf("@Patching %s with %s\n",pKern,pSize);
    if ((fKern != -1) && (fSize != -1)) {
      rSize = read(fSize,bSize,512); bSize[511] = 0x00;
      
      *kernSize = lseek(fKern,0,SEEK_END);
      *textSize = GetSize(bSize,".text");
      *dataSize = GetSize(bSize,".rodata");
      *kernSize = (*kernSize / (18*512) + 1); // Calc No. of Tracks to read
      
      memcpy((void *)(bKern+SIZEOFMARK+0x00),(void *)kernSize,4);
      memcpy((void *)(bKern+SIZEOFMARK+0x04),(void *)textSize,4);
      memcpy((void *)(bKern+SIZEOFMARK+0x08),(void *)dataSize,4);
      
      printf(" tracks     %.5ludec (%.8lXhex) \n",*kernSize,*kernSize);
      printf(" .text size %.5ludec (%.8lXhex) \n",*textSize,*textSize);
      printf(" .data size %.5ludec (%.8lXhex) \n",*dataSize,*dataSize);
      
      if (lseek(fKern,0,SEEK_SET) == 0) 
        if (write(fKern,bKern,512) == 512) {
          printf(" => successfully completed\n");
          xret = 0;
        }
        else
          printf(" #> impossible to write 512 Bytes to %s\n",pKern);
      else
        printf(" #> could not position file pointer to START OF FILE\n");
    }
    else
      printf(" #> either %s or %s could not be opened\n",pKern,pSize);
  }
  delete textSize;
  delete kernSize;
  delete dataSize;
  delete bSize;
  delete bKern;
  if (fSize != -1) close(fSize);
  if (fKern != -1) close(fKern);
  return xret;
}

int main(int argc, char **argv) {
  int xret = 1;
  Hello();
  if (argc > 2)   // !! KernPatch KernFile KernSize !!
    if (!Patch(argv[1],argv[2]))
      xret = 0;
  return xret;  
}