⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsys_pxe.c

📁 grub4dos-0.4.4-2008- 08-src.zip
💻 C
字号:
/* *  PXE file system for GRUB * *  Copyright (C) 2007 Bean (bean123@126.com) * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#ifdef FSYS_PXE#include "shared.h"#include "filesys.h"#include "pxe.h"#include "etherboot.h"#ifdef GRUB_UTILint pxe_mount(void) { return 0; }unsigned long pxe_read (char *buf, unsigned long len) { return -1; }int pxe_dir (char *dirname) { return 0; }void pxe_close (void) {}#else#ifndef TFTP_PORT#define TFTP_PORT	69#endif#define PXE_MIN_BLKSIZE	512#define PXE_MAX_BLKSIZE	1432#define DOT_SIZE	1048576#define PXE_BUF		FSYS_BUF#define PXE_BUFLEN	FSYS_BUFLEN//#define PXE_DEBUG	1unsigned long pxe_entry,pxe_blksize=PXE_MAX_BLKSIZE;unsigned short pxe_basemem,pxe_freemem;static IP4 pxe_yip,pxe_sip,pxe_gip;static UINT8 pxe_mac_len,pxe_mac_type,pxe_tftp_opened;static MAC_ADDR pxe_mac;static unsigned long pxe_saved_pos,pxe_cur_ofs,pxe_read_ofs,pxe_keep;static PXENV_TFTP_OPEN_t pxe_tftp_open;static char *pxe_tftp_name;extern unsigned long ROM_int15;extern struct drive_map_slot bios_drive_map[DRIVE_MAP_SIZE + 1];static char* pxe_outhex(char* pc,unsigned char c){  int i;  pc+=2;  for (i=1;i<=2;i++)    {      unsigned char t;      t=c & 0xF;      if (t>=10)        t+='A'-10;      else        t+='0';      *(pc-i)=t;      c=c>>4;    }  return pc;}void pxe_detect(void){  PXENV_GET_CACHED_INFO_t get_cached_info;  BOOTPLAYER *bp;  unsigned long tmp;  char *pc;  int i,ret;  if (! pxe_scan())    return;  pxe_basemem=*((unsigned short*)0x413);  get_cached_info.PacketType=PXENV_PACKET_TYPE_DHCP_ACK;  get_cached_info.Buffer=get_cached_info.BufferSize=0;  pxe_call(PXENV_GET_CACHED_INFO,&get_cached_info);  if (get_cached_info.Status)    return;  bp=LINEAR(get_cached_info.Buffer);  pxe_yip=bp->yip;  pxe_sip=bp->sip;  pxe_gip=bp->gip;  pxe_mac_type=bp->Hardware;  pxe_mac_len=bp->Hardlen;  grub_memmove(&pxe_mac,&bp->CAddr,pxe_mac_len);  get_cached_info.PacketType=PXENV_PACKET_TYPE_CACHED_REPLY;  get_cached_info.Buffer=get_cached_info.BufferSize=0;  pxe_call(PXENV_GET_CACHED_INFO,&get_cached_info);  if (get_cached_info.Status)    return;  bp=LINEAR(get_cached_info.Buffer);  if (bp->bootfile[0])    {      int n;      n=grub_strlen((char*)bp->bootfile)-1;      grub_strcpy((char*)&pxe_tftp_open.FileName,(char*)bp->bootfile);      while ((n>=0) && (pxe_tftp_open.FileName[n]!='/'))        n--;      if (n<0)        n=0;      pxe_tftp_name=(char*)&pxe_tftp_open.FileName[n];    }  else    pxe_tftp_name=(char*)&pxe_tftp_open.FileName[0];  pxe_tftp_opened=0;  ret=0;  grub_strcpy(pxe_tftp_name,"/menu.lst/");  pc=pxe_tftp_name+10;  pc=pxe_outhex(pc,pxe_mac_type);  for (i=0;i<pxe_mac_len;i++)    {      *(pc++)='-';      pc=pxe_outhex(pc,pxe_mac[i]);    }  *pc=0;  grub_printf("\n%s\n",pxe_tftp_open.FileName);  if (pxe_dir(pxe_tftp_name))    {      ret=1;      goto done;    }  pc=pxe_tftp_name+10;  tmp=pxe_yip;  for (i=0;i<4;i++)    {      pc=pxe_outhex(pc,tmp & 0xFF);      tmp >>=8;    }  *pc=0;  do    {      grub_printf("%s\n",pxe_tftp_open.FileName);      if (pxe_dir(pxe_tftp_name))        {          ret=1;          goto done;        }      *(--pc)=0;    } while (pc>pxe_tftp_name+10);  grub_strcpy(pc,"default");  grub_printf("%s\n",pxe_tftp_open.FileName);  ret=pxe_dir(pxe_tftp_name);done:  if (ret)    {      unsigned long nr;      nr=4096-1;      if (nr>filemax)        nr=filemax;      nr=pxe_read((char*)0x800,nr);      if (nr!=PXE_ERR_LEN)        {          *(char*)(0x800+nr)=0;          if (preset_menu!=(char*)0x800)            preset_menu=(char*)0x800;          if (nr<filemax)            {              grub_printf("Boot menu truncated\n");              pxe_read(NULL,filemax-nr);            }        }      pxe_close();    }  //getkey();}#if PXE_TFTP_MODEstatic int pxe_reopen(void){  pxe_close();  pxe_call(PXENV_TFTP_OPEN, &pxe_tftp_open);  if (pxe_tftp_open.Status)    return 0;  pxe_blksize=pxe_tftp_open.PacketSize;  pxe_tftp_opened=1;  pxe_saved_pos=pxe_cur_ofs=pxe_read_ofs=0;  return 1;}static int pxe_open(char* name){  PXENV_TFTP_GET_FSIZE_t *tftp_get_fsize;  tftp_get_fsize=(void*)&pxe_tftp_open;  tftp_get_fsize->ServerIPAddress=pxe_sip;  tftp_get_fsize->GatewayIPAddress=pxe_gip;  if (name!=pxe_tftp_name)    grub_strcpy(pxe_tftp_name,name);  pxe_call(PXENV_TFTP_GET_FSIZE,tftp_get_fsize);  if (tftp_get_fsize->Status)    return 0;  filemax=tftp_get_fsize->FileSize;  pxe_tftp_open.TFTPPort=htons(TFTP_PORT);  pxe_tftp_open.PacketSize=pxe_blksize;  return pxe_reopen();}void pxe_close(void){  if (pxe_tftp_opened)    {      PXENV_TFTP_CLOSE_t tftp_close;      pxe_call(PXENV_TFTP_CLOSE,&tftp_close);      pxe_tftp_opened=0;    }}#if PXE_FAST_READ/* Read num packets , BUF must be segment aligned*/static unsigned long pxe_read_blk(unsigned long buf,int num){  PXENV_TFTP_READ_t tftp_read;  unsigned long ofs;  tftp_read.Buffer=SEGOFS(buf);  ofs=tftp_read.Buffer & 0xFFFF;  pxe_fast_read(&tftp_read, num);  return (tftp_read.Status)?PXE_ERR_LEN:((tftp_read.Buffer & 0xFFFF)-ofs);}#elsestatic unsigned long pxe_read_blk(unsigned long buf,int num){  PXENV_TFTP_READ_t tftp_read;  unsigned long ofs;  tftp_read.Buffer=SEGOFS(buf);  ofs=tftp_read.Buffer & 0xFFFF;  while (num>0)    {      pxe_call(PXENV_TFTP_READ, &tftp_read);      if (tftp_read.Status)        return PXE_ERR_LEN;      tftp_read.Buffer+=tftp_read.BufferSize;      if (tftp_read.BufferSize<pxe_blksize)        break;      num--;    }  return (tftp_read.Buffer & 0xFFFF) - ofs;}#endif#else#endifstatic unsigned long pxe_read_len (char* buf, unsigned long len){  unsigned long old_ofs,sz;  if (len==0)    return 0;  sz=0;  old_ofs=pxe_cur_ofs;  pxe_cur_ofs+=len;  if (pxe_cur_ofs>pxe_read_ofs)    {      unsigned long nb,nr;      long nb_del,nb_pos;      sz=(pxe_read_ofs-old_ofs);      if ((buf) && (sz))        {          grub_memmove(buf,(char*)(PXE_BUF+old_ofs),sz);          buf+=sz;        }      pxe_cur_ofs-=pxe_read_ofs;      nb=pxe_cur_ofs / pxe_blksize;      nb_del=DOT_SIZE / pxe_blksize;      if (nb_del>nb)        {          nb_del=0;          nb_pos=-1;        }      else        nb_pos=nb-nb_del;      pxe_cur_ofs-=pxe_blksize*nb;      if (pxe_read_ofs+pxe_blksize>PXE_BUFLEN)        pxe_read_ofs=0;      while (nb>0)        {          unsigned long nn;          nn=(PXE_BUFLEN - pxe_read_ofs) / pxe_blksize;          if (nn>nb)            nn=nb;          nr=pxe_read_blk(PXE_BUF+pxe_read_ofs,nn);          if (nr==PXE_ERR_LEN)            return nr;          sz+=nr;          if (buf)            {              grub_memmove(buf,(char*)(PXE_BUF+pxe_read_ofs),nr);              buf+=nr;            }          if (nr<nn*pxe_blksize)            {              pxe_read_ofs+=nr;              pxe_cur_ofs=pxe_read_ofs;              return sz;            }          nb-=nn;          if (nb)            pxe_read_ofs=0;          else            pxe_read_ofs+=nr;          if ((long)nb<=nb_pos)            {              grub_putchar('.');              nb_pos-=nb_del;            }        }      if (nb_del)        {          grub_putchar('\r');          grub_putchar('\n');        }      if (pxe_cur_ofs)        {          if (pxe_read_ofs+pxe_blksize>PXE_BUFLEN)            pxe_read_ofs=0;          nr=pxe_read_blk(PXE_BUF+pxe_read_ofs,1);          if (nr==PXE_ERR_LEN)            return nr;          if (pxe_cur_ofs>nr)            pxe_cur_ofs=nr;          sz+=pxe_cur_ofs;          if (buf)            grub_memmove(buf,(char*)(PXE_BUF+pxe_read_ofs),pxe_cur_ofs);          pxe_cur_ofs+=pxe_read_ofs;          pxe_read_ofs+=nr;        }      else        pxe_cur_ofs=pxe_read_ofs;    }  else    {      sz+=len;      if (buf)        grub_memmove(buf,(char*)PXE_BUF+old_ofs,len);    }  return sz;}/* Mount the network drive. If the drive is ready, return 1, otherwise   return 0. */int pxe_mount(void){  if (current_drive != PXE_DRIVE)    return 0;  return 1;}/* Read up to SIZE bytes, returned in ADDR.  */unsigned long pxe_read (char *buf, unsigned long len){  unsigned long nr;  if (! pxe_tftp_opened)    return PXE_ERR_LEN;  if (pxe_saved_pos!=filepos)    {      if ((filepos<pxe_saved_pos) && (filepos+pxe_cur_ofs>=pxe_saved_pos))        pxe_cur_ofs-=pxe_saved_pos-filepos;      else        {          if (pxe_saved_pos>filepos)            {              //grub_printf("reopen\n");              if (! pxe_reopen())                return PXE_ERR_LEN;            }          nr=pxe_read_len(NULL, filepos-pxe_saved_pos);          if ((nr==PXE_ERR_LEN) || (pxe_saved_pos+nr!=filepos))            return PXE_ERR_LEN;        }      pxe_saved_pos=filepos;    }  nr=pxe_read_len(buf,len);  if (nr!=PXE_ERR_LEN)    {      filepos+=nr;      pxe_saved_pos=filepos;    }  return nr;}/* Check if the file DIRNAME really exists. Get the size and save it in   FILEMAX. return 1 if succeed, 0 if fail.  */int pxe_dir (char *dirname){  int ret,ch;  if (print_possibilities)    return 1;  pxe_close();  ret=1;  ch=nul_terminate(dirname);  if (! pxe_open(dirname))    {      errnum=ERR_FILE_NOT_FOUND;      ret=0;    }  dirname[grub_strlen(dirname)]=ch;  return ret;}void pxe_unload(void){  PXENV_UNLOAD_STACK_t unload;  unsigned char code[]={PXENV_UNDI_SHUTDOWN,PXENV_UNLOAD_STACK,PXENV_STOP_UNDI,0};  int i,h;  if (! pxe_entry)    return;  pxe_close();  if (pxe_keep)    return;  h=unset_int13_handler(1);  if (! h)    unset_int13_handler(0);  i=0;  while (code[i])    {      grub_memset(&unload,0,sizeof(unload));      pxe_call(code[i],&unload);      if (unload.Status)        {          grub_printf("PXE unload fails: %d\n",unload.Status);          goto quit;        }      i++;    }  if (*((unsigned short*)0x413)==pxe_basemem)    *((unsigned short*)0x413)=pxe_freemem;  pxe_entry=0;  ROM_int15=*((unsigned long*)0x54);  grub_printf("PXE stack unloaded\n");quit:  if (! h)    set_int13_handler(bios_drive_map);}static void print_ip(IP4 ip){  int i;  for (i=0;i<3;i++)    {      grub_printf("%d.",ip & 0xFF);      ip>>=8;    }  grub_printf("%d",ip);}int pxe_func(char* arg,int flags){  if (! pxe_entry)    {      grub_printf("No PXE stack\n");      errnum = ERR_BAD_ARGUMENT;      return 1;    }  if (*arg==0)    {      char buf[4],*pc;      int i;      pxe_tftp_name[0]='/';      pxe_tftp_name[1]=0;      grub_printf("blksize : %d\n",pxe_blksize);      grub_printf("basedir : %s\n",pxe_tftp_open.FileName);      grub_printf("client ip  : ");      print_ip(pxe_yip);      grub_printf("\nserver ip  : ");      print_ip(pxe_sip);      grub_printf("\ngateway ip : ");      print_ip(pxe_gip);      grub_printf("\nmac : ");      for (i=0;i<pxe_mac_len;i++)        {          pc=buf;          pc=pxe_outhex(pc,pxe_mac[i]);          *pc=0;          grub_printf("%s%c",buf,(i==pxe_mac_len-1)?'\n':'-');        }    }  else if (grub_memcmp(arg, "blksize", sizeof("blksize")-1)==0)    {      int val;      arg=skip_to(0, arg);      if (! safe_parse_maxint(&arg, &val))        return 1;      if (val>PXE_MAX_BLKSIZE)        val=PXE_MAX_BLKSIZE;      if (val<PXE_MIN_BLKSIZE)        val=PXE_MIN_BLKSIZE;      pxe_blksize=val;    }  else if (grub_memcmp(arg, "basedir", sizeof("basedir")-1)==0)    {      int n;      arg=skip_to(0, arg);      if (*arg==0)        {          grub_printf("No pathname\n");          errnum = ERR_BAD_ARGUMENT;          return 1;        }      if (*arg!='/')        {          grub_printf("Base directory must start with /\n");          errnum = ERR_BAD_ARGUMENT;          return 1;        }      n=grub_strlen(arg);      if (n>sizeof(pxe_tftp_open.FileName)-8)        {          grub_printf("Path too long\n");          errnum = ERR_BAD_ARGUMENT;          return 1;        }      grub_strcpy((char*)pxe_tftp_open.FileName,arg);      n--;      while ((n>=0) && (pxe_tftp_open.FileName[n]=='/'))        n--;      pxe_tftp_name=(char*)&pxe_tftp_open.FileName[n+1];    }  else if (grub_memcmp(arg, "keep", sizeof("keep")-1)==0)    pxe_keep=1;  else if (grub_memcmp(arg, "unload", sizeof("unload")-1)==0)    {      pxe_keep=0;      pxe_unload();    }#ifdef PXE_DEBUG  else if (grub_memcmp(arg, "dump", sizeof("dump")-1)==0)    {      PXENV_GET_CACHED_INFO_t get_cached_info;      BOOTPLAYER *bp;      int val;      arg=skip_to(0, arg);      if (! safe_parse_maxint(&arg, &val))        return 1;      if ((val<1) || (val>3))        {          grub_printf("Invalid type\n");          errnum = ERR_BAD_ARGUMENT;          return 1;        }      get_cached_info.PacketType=val;      get_cached_info.Buffer=get_cached_info.BufferSize=0;      pxe_call(PXENV_GET_CACHED_INFO,&get_cached_info);      if (get_cached_info.Status)        return;      bp=LINEAR(get_cached_info.Buffer);      grub_printf("%X\n",(unsigned long)bp);      hexdump(0,bp,get_cached_info.BufferSize);    }#endif  else    {      errnum = ERR_BAD_ARGUMENT;      return 1;    }  return 0;}#endif#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -