Difference between pages "Whenjobs" and "PXE Network Windows Installation"

From Funtoo
(Difference between pages)
Jump to: navigation, search
(whenjobs commands)
 
(Creating a Setup Instruction File)
 
Line 1: Line 1:
== What are whenjobs ==
+
''Howto use your Funtoo machine to serve a MS Windows installation over the network''
 +
In this guide we will assume that you have followed the [[PXE network boot server]] Wiki article and have a working network/pxe boot setup. As of now this guide will cover Windows XP. Soon it will be expanded to also cover Windows 7.
 +
==Prerequisites==
 +
#A working Funtoo installation
 +
#A working PXE Setup (DHCP, TFTP, PXELinux)
 +
#app-arch/cabextract
 +
#A legitimate copy of Microsoft Windows
 +
#Driver for your NIC - ''Suggested to use a complete driver pack with all major supported NIC hardware for the version of Windows to be installed.''
 +
#RIS Linux toolkit >=0.4
 +
#A working Samba server setup
  
{{fancywarning|This document is a work in progress, as we are still investigating whenjobs for funtoo usage. For information about it see Funtoo tickets about [http://bugs.funtoo.org/browse/FL-316 whenjobs], [http://bugs.funtoo.org/browse/FL-337 initscript], [http://bugs.funtoo.org/browse/FL-338 User Feedback] and [http://bugs.funtoo.org/browse/FL-351 this document].}}
+
== Creating the Windows XP Image ==
  
Whenjobs are written by Richard Jones from [http://www.redhat.com RedHat Linux]. They are designed to be a cron daemon replacement with some improvements over normal cron-jobs. Further more we from Funtoo Linux added some improvements to them already. Whenjobs give users a simpler syntax for jobs to run and with funtoo improvements a good way of user-management for whenjobs, that way we fixed the default behaviour of whenjobs to not been able to run as root and let us execute the daemon on a userbasis by default.
+
*In the previous guide, [http://www.funtoo.org/wiki/PXE_network_boot_server PXE Network Boot Server], we used /tftproot as the working directory so we will also use it in this guide for convenience. If you chose to use a different working directory then please apply it where needed in place of the /tftproot we will be going by here.
  
=== Question for help and testing ===
+
First you will need to create an ISO from your Windows XP installation disc. If you already have the ISO image you may skip this step.  
 
+
With this tutorial we like to ask users to help us and test whenjobs. We would like to get your feedback to [http://bugs.funtoo.org/browse/FL-338 FL-338]. So please test and report there what you think and what you think should be improved.
+
 
+
== How to install whenjobs ==
+
 
+
The installation of whenjobs is really easy, just merge them and you would get all that is needed for a first testrun and later perhaps also a production usage.
+
  
 
<console>
 
<console>
# ##i##emerge -avt whenjobs
+
###i## dd if=/dev/sr0 of=/tftproot/winxp.iso
 
</console>
 
</console>
 +
If your cdrom device isn't ''<code>/dev/sr0</code>'' please use the appropriate device in this command.
  
That's what is needed for installing whenjobs, nothing big so far.
+
== Mount the ISO and Prepare Installation Sources ==
 
+
Mount the image to ''<code>/tftproot/cdrom</code>'':  
== How to get started ==
+
 
+
As mentioned above we added a user-management and whenjobs has a changed syntax compared to normal cronjobs so we will discuss all these parts now. :)
+
 
+
=== user management ===
+
 
+
The user management for whenjobs is done with a single file located at '''/etc/whenjobs.users.conf''' just add a user to that file by a commaseperated list like
+
 
+
<pre>
+
root,user1,user2,user3
+
</pre>
+
 
+
where user1-user3 have to be system-usernames as they are checked. please do not add any other lines to that file, as there is atm now way for comments in the file and adding other lines will break so far the usage and you won't be able to start the daemon later. ATM there is no initscript, but we are working on one and that initscript will then use that file in the same way. :)
+
 
+
=== whenjobs commands ===
+
 
+
There are some basic commands for whenjobs you should be aware of before we get to explain the script syntax for whenjobs. this part will explain them.
+
 
+
To edit/list a job script, use:
+
 
<console>
 
<console>
# ##i##whenjobs -e | --edit
+
###i## mkdir /tftproot/cdrom; mount -o loop /tftproot/winxp.iso /tftproot/cdrom
# ##i##whenjobs -l | --list
+
 
</console>
 
</console>
 
+
Create the new directory for the network installation files and copy the needed files to it:
in the above case we added both the short and long version in one line so please use either the '''-e''' or the '''--edit''' version as there is no piping done at that part. We will use the same syntax for further examples if there are multiple ways of calling the function we need.
+
 
+
Another import part is to set or get variables we want to set or set in whenjobs, that can be done with:
+
 
+
 
<console>
 
<console>
to get a variable:
+
###i## mkdir /tftproot/winxp; cp -R /tftproot/cdrom/i386 /tftproot/winxp/i386
###i## whenjobs --get variable
+
to set a variable or multiple varibles:
+
###i## whenjobs --set variable=value [variable=value ...]
+
and to display all set variables:
+
###i## whenjobs --variables
+
 
</console>
 
</console>
 
+
Depending on your CD/DVD copy of windows the directory name may be I386 as opposed to i386, if that is the case you will just need to change the first part of the command, keeping the new directory name i386 - this is going to be very important later on when creating the remap file!
Another important function in whenjobs is the way to start, stop and request the status of the per-user daemon:
+
Check the contents of your newly created i386 directory to see if the filenames are in all CAPS or if they are already in lowercase.
 +
<console>
 +
###i## ls /tftproot/winxp/i386
 +
</console>
 +
If you happen to have all UPPERCASE filenames, lets go ahead and run a script to convert it to all lowercase:
 
<console>
 
<console>
# ##i##whenjobs --daemon-start
+
###i## cd /tftproot/winxp/i386;ls | awk '$0!=tolower($0){printf "mv \"%s\" \"%s\"\n",$0,tolower($0)}' | sh
# ##i##whenjobs --daemon-stop
+
# ##i##whenjobs --daemon-status
+
# ##i##whenjobs --daemon-restart
+
 
</console>
 
</console>
  
Finally we have the ability to inspect running jobs:
+
==Extracting and Modifying the Required Boot Files ==
 +
Install {{Package|app-arch/cabextract}}
 
<console>
 
<console>
# ##i##whenjobs --jobs
+
###i## emerge -av app-arch/cabextract
# ##i##whenjobs --cancel serial
+
</console>
# ##i##whenjobs --start "name"
+
Extract the prepackaged drivers:
# ##i##whenjobs --tail serial
+
<console>
 +
###i## cd /tftproot/winxp/i386;cabextract driver.cab
 +
</console>
 +
Install support for a large list of network cards:
 +
<console>
 +
###i## cd /tftproot/;wget http://downloads.sourceforge.net/project/bootfloppy/pxefiles.tar.gz
 +
###i## tar zxvf pxefiles.tar.gz; cp pxefiles/drivers/* winxp/i386/
 +
</console>
 +
Copy the BINLSRV /INFParser tools to /tftproot:
 +
<console>
 +
###i## cp pxefiles/script/* /tftproot/
 +
</console>
 +
Extract the netboot startrom:
 +
<console>
 +
###i## cd /tftproot; cabextract winxp/i386/startrom.n1_
 +
</console>
 +
Fix the startrom for netbooting xp:
 +
<console>
 +
###i## sed -i -e 's/NTLDR/XPLDR/gi' startrom.n12
 +
###i## mv startrom.n12 winxp.0
 +
</console>
 +
Fix XPLDR:
 +
<console>
 +
###i## cabextract winxp/i386/setupldr.ex_
 +
###i## sed -i -e 's/winnt\.sif/winxp\.sif/gi' setupldr.exe
 +
###i## sed -i -e 's/ntdetect\.com/ntdetect\.wxp/gi' setupldr.exe
 +
###i## mv setupldr.exe xpldr
 +
###i## cp winxp/i386/ntdetect.com ntdetect.wxp
 
</console>
 
</console>
  
=== How to get started with whenjobs now ===
+
== Creating a remapping file ==
 
+
Create the file <code>/tftproot/tftpd.remap</code> and add the following to it:
First edit the above mentioned '''whenjobs.users.conf''' file if not already done and start a daemon on a per-user basis with
+
{{File
 +
|/tftproot/tftpd.remap|<pre>
 +
ri ^[az]: # Remove “drive letters”
 +
rg \\ / # Convert backslashes to slashes
 +
rg \# @ # Convert hash marks to @ signs
 +
rg /../ /..no../ # Convert /../ to /..no../
 +
rg A a
 +
rg B b
 +
rg C c
 +
rg D d
 +
rg E e
 +
rg F f
 +
rg G g
 +
rg H h
 +
rg I i
 +
rg J j
 +
rg K k
 +
rg L l
 +
rg M m
 +
rg N n
 +
rg O o
 +
rg P p
 +
rg Q q
 +
rg R r
 +
rg S s
 +
rg T t
 +
rg U u
 +
rg V v
 +
rg W w
 +
rg X x
 +
rg Y y
 +
rg Z z
 +
r ^/(.*) \1
 +
r ^xpldr xpldr
 +
r ^ntdetect.wxp ntdetect.wxp
 +
r ^winxp.sif winxp.sif
 +
</pre>}}
  
 +
==Install/Configure Samba ==
 +
If you don't already have {{Package|net-fs/samba}} installed, then:
 
<console>
 
<console>
# ##i##whenjobs --daemon-start
+
###i## emerge -av net-fs/samba
 
</console>
 
</console>
 +
Create a Samba share for your tftp server in <code>/etc/samba/smb.conf</code>
  
Thats all for starting whenjobs and now we have time to write some whenjobs-scripts. We will use here some basic examples nothing for real time usage but it should be able to give you the impression on how to write your own scripts and use the variables in the later process. First we need to edit our whenjobs-script. This can be done by two ways:
+
{{Note}} Be sure you have the other required samba settings configured in the file
 +
{{File
 +
|/etc/samba/smb.conf|<pre>
 +
[Global]
 +
interfaces = lo eth0 wlan0
 +
bind interfaces only = yes
 +
workgroup = WORKGROUP
 +
security = user
  
 +
[tftproot]
 +
path = /tftproot
 +
browsable = true
 +
read only = yes
 +
writable = no
 +
guest ok = yes
 +
</pre>}}
 +
Start Samba:
 
<console>
 
<console>
Version A) (manual way, not recommended)
+
###i## /etc/init.d/samba start
# ##i##EDITOR ~/.whenjobs/jobs.ml
+
</console> 
Edit the file with the scripts you want to use and save it, but after that you need to upload it so that whenjobs knows about it
+
or if samba has already been started:
# ##i##whenjobs --upload
+
<console>
Version B) (automatically by whenjobs, recommended)
+
###i## /etc/init.d/samba restart
# ##i##whenjobs -e  | --edit
+
just save your script now and whenjobs will upload it automatically for you.
+
 
</console>
 
</console>
  
So far we are now fine with getting to the scripts, next let us add some basics. We will now start with a periodic call, like if we would like to check out load everyage every 10 minutes we would do it like this:
+
== Creating a Setup Instruction File ==
 +
Create the file <code>/tftproot/winxp.sif</code> and add the following, replacing <tt>SAMBA_SERVER_IP</tt> with the local IP address of your samba server:
 +
{{File
 +
|/tftproot/winxp.sif|<pre>
 +
[data]
 +
floppyless = "1"
 +
msdosinitiated = "1"
 +
; Needed for second stage
 +
OriSrc = "\\SAMBA_SERVER_IP\tftproot\winxp\i386"
 +
OriTyp = "4"
 +
LocalSourceOnCD = 1
 +
DisableAdminAccountOnDomainJoin = 1
  
{{fancywarning|A note aside, the scripts are real shell scripts, so parts beginning with a '''#''' are comments and parts without are the shell script commands that are executed!}}
+
[SetupData]
 +
OsLoadOptions = "/fastdetect"
 +
; Needed for first stage
 +
SetupSourceDevice = "\Device\LanmanRedirector\SAMBA_SERVER_IP\tftproot\winxp"
  
<source lang="ocaml">
+
[UserData]
every 10 minutes :
+
ComputerName = *
<<
+
</pre>}}
  # Get the current load average.
+
  load=`awk '{print $1}' /proc/loadavg`
+
  whenjobs --set --type float load=$load
+
>>
+
</source>
+
  
The power of whenjobs comes in game when you would like to base on a variable you set somewhere else:
+
== Editing the pxelinux.cfg/default boot menu ==
 +
Edit your boot menu so that it contains the following entry:
 +
<console>
 +
LABEL WinXP
 +
MENU LABEL Install MS Windows XP
 +
KERNEL winxp.0
 +
</console>
  
<source lang="ocaml">
+
== Re-Start all required daemons ==
when load >= 6 :
+
If the daemon isn't already running use start instead or restart in the following commands
<<
+
<console>
  mail -s "ALERT: high load average: $load" MAILADDRESS < /dev/null
+
###i## /etc/init.d/dnsmasq restart
>>
+
###i## /etc/init.d/in.tftpd restart
</source>
+
</console>
  
That part will notify a user via email when his load average is greater or equal to 6, as when statements are "edge-triggered".
+
== Modify Binlsrv, update driver cache, and start driver hosting service ==
 
+
Change the BASEPATH= variable at or around line #62 of ''<code>binlsrv.py</code>'' so that it is:
The '''--type''' switch above for setting a variable can be one of '''bool, int, float, string or unit'''
+
<console>
 
+
###i## nano binlsrv.py
==== Periodic expressions ====
+
BASEPATH='/tftproot/winxp/i386/'
 
+
</console>
For periodic expressions you have to use the following syntax
+
Generate driver cache:
 
+
<console>
<source lang="ocaml">
+
###i## cd /tftproot;./infparser.py winxp/i386/
every <period> :
+
</console>
<<
+
Start binlservice:
  # shell script
+
<console>
>>
+
###i## ./binlsrv.py
</source>
+
</console>
 
+
where '''<period>''' is one of the following period expressions:
+
 
+
{| class="wikitable"
+
! <period>
+
! Description
+
!
+
! Special <period>
+
! Description
+
|-
+
| second
+
| runs every second
+
|
+
| X seconds
+
| runs every X seconds
+
|-
+
| minute
+
| runs every minute
+
|
+
| X minutes
+
| runs every X minutes
+
|-
+
| hour
+
| runs every hour
+
|
+
| X hours
+
| runs every X hours
+
|-
+
| day
+
| runs every day, at midnight UTC
+
|
+
| X days
+
| runs every X days, at midnight UTC
+
|-
+
| week
+
| runs every week, on a Thursday at midnight UTC
+
|
+
| X weeks
+
| runs every X weeks, on a Thursday at midnight UTC
+
|-
+
| month
+
| runs every month, on the 1st at midnight UTC
+
|
+
| X months
+
| runs every X month, on the 1st at midnight UTC
+
|-
+
| year
+
| runs every year, on the 1/1 at midnight UTC
+
|
+
| X years
+
| runs every X years, on the 1/1 at midnight UTC
+
|-
+
| decade
+
| runs every 10 years
+
|
+
| X decades
+
| runs every X decades
+
|-
+
| century
+
| runs every 100 years
+
|
+
| X centuries
+
| runs every X centuries
+
|-
+
| millenium
+
| runs every 1000 years
+
|
+
| X millenia
+
| runs every X mellenia
+
|}
+
 
+
==== When expressions ====
+
 
+
For dependent jobs you need to use the when-statements with the following syntax:
+
 
+
<source lang="ocaml">
+
when <expr> :
+
<<
+
  # shell script
+
>>
+
</source>
+
 
+
where '''<expr>''' is a when expression. But don't forget the colon between periods expression or when expression and the shell script.
+
 
+
All in all you can say, that a when-expression is a job which runs, when the described conditions become true.
+
 
+
{| class="wikitable"
+
! <expr>
+
! meaning
+
!
+
! <expr>
+
! meaning
+
|-
+
| expr && expr
+
| boolean "and" of the two sub-expressions
+
|
+
| ! expr
+
| boolean negative of expr
+
|-
+
| expr <nowiki>||</nowiki> expr
+
| boolean "or" of the two sub-expressions
+
|
+
| expr + expr
+
| for numeric sub-expression, this performs addition, for strings it performs string concatenation, else it returns an error.
+
|-
+
| expr < expr
+
| evaluates sub-expressions and compares them with the operator
+
|
+
| expr - expr
+
| evaluates sub-expressions and if both are numeric uses operator on them else returns error
+
|-
+
| expr <= expr
+
| evaluates sub-expressions and compares them with the operator
+
|
+
| expr * expr
+
| evaluates sub-expressions and if both are numeric uses operator on them else returns error
+
|-
+
| expr == expr
+
| evaluates sub-expressions and compares them with the operator
+
|
+
| expr / expr
+
| evaluates sub-expressions and if both are numeric uses operator on them else returns error
+
|-
+
| expr >= expr
+
| evaluates sub-expressions and compares them with the operator
+
|
+
| expr mod expr
+
| evaluates sub-expressions and if both are numeric uses operator on them else returns error (infix operator)
+
|-
+
| expr > expr
+
| evaluates sub-expressions and compares them with the operator
+
|
+
| len expr
+
| returns the length of the string in expr
+
|-
+
| variable
+
| returns the value of named variable
+
|
+
| prev variable
+
| returns previous value of named variable
+
|-
+
| changes variable
+
| same as !(prev variabel == variable)
+
|
+
| increases variable
+
| same as prev variable < variable
+
|-
+
| decreases variable
+
| prev variable > variable
+
|
+
| reloaded ()
+
| do not use it, it does not what you want (manpage warning)
+
|-
+
| false
+
| constant equals always false
+
|
+
| true
+
| constant equals always true
+
|-
+
| "any string"
+
| empty string in boolean = false, else equals true
+
|
+
| N
+
| any integer, boolean 0=false, non-zero=true
+
|-
+
| N. | .N | N.N | N.NeN
+
| and floating point number, boolean 0=false, non-zero=true
+
|
+
|
+
|
+
|}
+
 
+
==== shell scripts ====
+
 
+
The code between '''<< ... >>''' is a simple shell script and is executed using $SHELL. If $SHELL is not set, it is executed with '''/bin/sh'''
+
 
+
{| class="wikitable"
+
! available variable
+
! Description
+
|-
+
| $JOBNAME
+
| The name of the job. If the job has been named explicitly, then that name is available through this variable, else it will be some implicit name like '''job$1'''.
+
|-
+
| $JOBSERIAL
+
| The serial number of the job. This is simply a variable that increments each time a job is run, and is unique to that run of the job.
+
|-
+
| $HOME, $LOGNAME etc
+
| these are available as normal
+
|}
+
 
+
The shell scripts run with its current directory set to an temporary directory, that is cleaned up automacically after the job exists. So you don't have to worry about cleaning them up later. If you would like to store some values permanently, save the files to a well-known directory, eg. $HOME, '''/var''' etc.
+
 
+
All shell scripts are executed as the ordinary user. They have no special privileges.
+
 
+
==== Job names ====
+
 
+
If you like to give a job a unique name use the following syntax:
+
 
+
<source lang="ocaml">
+
job "JOBNAME"
+
every <period> :
+
<<
+
  # shell script
+
>>
+
</source>
+
 
+
==== OCAML expressions ====
+
 
+
You can also use OCAML expressions in the code. they are useful for factoring common code or strings, for example:
+
 
+
<source lang="ocaml">
+
let prefix = "daily_"
+
 
+
job (prefix ^ "virus_scan")
+
every day :
+
<<
+
  # shell script
+
>>
+
 
+
job (prefix ^ "disk_check")
+
every day :
+
<<
+
  # shell script
+
>>
+
</source>
+
 
+
===== initial value of variables =====
+
 
+
Variables are empty until they first get set, you can set a default starting value for a variable if you like with the following code
+
 
+
<source lang="ocaml">
+
let () =
+
  Whentools.set_variable "variable" "value";
+
  Whentools.set_variable_int "counter" 0
+
</source>
+
 
+
===== Pre functions =====
+
 
+
You can let arrange to run a '''pre''' function before a job runs. This function may decide to not run the job. One possible usage for that is the that you only want to have one job at time from the same job to run:
+
 
+
<source lang="ocaml">
+
job "only one"
+
pre (Whentools.one ())
+
every <period> :
+
<<
+
  # shell script
+
>>
+
</source>
+
 
+
===== Post functions =====
+
 
+
The same is for stuff after a job has run. This is handled by the '''post''' function.
+
 
+
<source lang="ocaml">
+
job "talk to me after finished"
+
post (Whentools.mailto "you@example.com")
+
every <period> :
+
<<
+
  # shell script
+
>>
+
</source>
+
 
+
===== Basic available Whentools functions =====
+
 
+
{| class="wikitable"
+
! function
+
! Description
+
|-
+
| style="vertical-align:top;"| whentools.mailto [~only_on_failure:true] [~from:from_address] email_address result
+
| This built-in post function sends the result of the script by email to the given email address.
+
 
+
If the optional "~only_on_failure:true" flag is set, then it is only sent out if the script failed.
+
 
+
If the optional "~from" flag is set, then the from address is set accordingly.  This is sometimes needed when sending mail.
+
 
+
Note the "result" parameter is passed implicitly by the daemon. You do not need to add it.
+
 
+
Here are some examples of using the mailto function:
+
 
+
<source lang="ocaml">
+
job "ex.1"
+
post (Whentools.mailto "you@example.com")
+
every 10 seconds :
+
<<
+
  # shell script 1
+
>>
+
 
+
job "ex.2"
+
post (Whentools.mailto ~only_on_failure:true "you@example.com")
+
every 10 seconds :
+
<<
+
  # shell script 2
+
>>
+
 
+
let from = "me@example.com"
+
let to_addr = "you@example.com"
+
 
+
job "ex.3"
+
post (Whentools.mailto ~from to_addr)
+
every 10 seconds :
+
<<
+
  # shell script 3
+
>>
+
</source>
+
|-
+
| style="vertical-align:top;"| Whentools.max n
+
| This built-in pre function ensures that a maximum of n instances of the job are running.
+
 
+
It checks the list of running jobs, and if n or more instances are already running, then it returns "false", which ensures that the new job is not started.
+
|-
+
| style="vertical-align:top;"| Whentools.one ()
+
| This built-in pre function ensures that only one instance of the job is running.  It is the same as calling: Whentools.max 1
+
 
+
|-
+
| style="vertical-align:top;"| Whentools.set_variable name string
+
| Set variable name to the string
+
|-
+
| Whentools.set_variable_bool name b
+
| Set variable name to the boolean value b
+
|-
+
| style="vertical-align:top;"| Whentools.set_variable_int name i
+
| Set variable name to the integer value i
+
|-
+
| style="vertical-align:top;"| Whentools.set_variable_string name s
+
| Set variable name to the string value <s>.  This is the same as Whentools.set_variable
+
|-
+
| style="vertical-align:top;"| Whentools.set_variable_float name f
+
| Set variable name to the floating point value f
+
|}
+
 
+
For the preinfo passed to the pre functions and results for the post functions have a view in the manpage.
+
 
+
== Examples ==
+
 
+
Finally here are some examples to which questions came up, hope you find them helpful for your first own tries... :)
+
 
+
<source lang="ocaml">
+
every 1 minute :
+
<<
+
  testtime=`date +%H%M`
+
  whenjobs --set --type int test=${testtime}
+
  whenjobs --set --type int runtime=0016
+
>>
+
 
+
when test == 0017 :
+
<<
+
  echo `date` >\> ~/test.log
+
>>
+
 
+
when test == runtime
+
<<
+
  whenjobs --get runtime >\> ~/test.log
+
>>
+
</source>
+
 
+
The above whenjobs have the need to run each day at a specific time, so we show you here two ways of doing it.
+
 
+
First we define a variable test for whenjobs based on the date with the HHMM output what would for example result in 0017 for 12:17am and 1428 for 2:28pm. then in the first when expression we test if our variable equals 0017 and if yes it runs, the second version is to define a second variable called runtime and then do like the second test does a test for it based on comparing both variables.
+
 
+
But now enough with that long doc, happy whenjobing for all of you... :)
+
  
 +
== Booting the client ==
 +
If all is well, you should be able to boot the client choosing to ''boot from network'' in the boot options, you should get to your PXELinux bootloader, and see the Install Windows XP option after pressing enter you *should* kick off your XP installation via network!! Congratulations!
  
 
[[Category:HOWTO]]
 
[[Category:HOWTO]]
[[Category:Labs]]
 
[[Category:Featured]]
 

Revision as of 23:52, 14 January 2014

Howto use your Funtoo machine to serve a MS Windows installation over the network In this guide we will assume that you have followed the PXE network boot server Wiki article and have a working network/pxe boot setup. As of now this guide will cover Windows XP. Soon it will be expanded to also cover Windows 7.

Contents

Prerequisites

  1. A working Funtoo installation
  2. A working PXE Setup (DHCP, TFTP, PXELinux)
  3. app-arch/cabextract
  4. A legitimate copy of Microsoft Windows
  5. Driver for your NIC - Suggested to use a complete driver pack with all major supported NIC hardware for the version of Windows to be installed.
  6. RIS Linux toolkit >=0.4
  7. A working Samba server setup

Creating the Windows XP Image

  • In the previous guide, PXE Network Boot Server, we used /tftproot as the working directory so we will also use it in this guide for convenience. If you chose to use a different working directory then please apply it where needed in place of the /tftproot we will be going by here.

First you will need to create an ISO from your Windows XP installation disc. If you already have the ISO image you may skip this step.

# dd if=/dev/sr0 of=/tftproot/winxp.iso

If your cdrom device isn't /dev/sr0 please use the appropriate device in this command.

Mount the ISO and Prepare Installation Sources

Mount the image to /tftproot/cdrom:

# mkdir /tftproot/cdrom; mount -o loop /tftproot/winxp.iso /tftproot/cdrom

Create the new directory for the network installation files and copy the needed files to it:

# mkdir /tftproot/winxp; cp -R /tftproot/cdrom/i386 /tftproot/winxp/i386

Depending on your CD/DVD copy of windows the directory name may be I386 as opposed to i386, if that is the case you will just need to change the first part of the command, keeping the new directory name i386 - this is going to be very important later on when creating the remap file! Check the contents of your newly created i386 directory to see if the filenames are in all CAPS or if they are already in lowercase.

# ls /tftproot/winxp/i386

If you happen to have all UPPERCASE filenames, lets go ahead and run a script to convert it to all lowercase:

# cd /tftproot/winxp/i386;ls | awk '$0!=tolower($0){printf "mv \"%s\" \"%s\"\n",$0,tolower($0)}' | sh

Extracting and Modifying the Required Boot Files

Install app-arch/cabextract

# emerge -av app-arch/cabextract

Extract the prepackaged drivers:

# cd /tftproot/winxp/i386;cabextract driver.cab

Install support for a large list of network cards:

# cd /tftproot/;wget http://downloads.sourceforge.net/project/bootfloppy/pxefiles.tar.gz
# tar zxvf pxefiles.tar.gz; cp pxefiles/drivers/* winxp/i386/

Copy the BINLSRV /INFParser tools to /tftproot:

# cp pxefiles/script/* /tftproot/

Extract the netboot startrom:

# cd /tftproot; cabextract winxp/i386/startrom.n1_

Fix the startrom for netbooting xp:

# sed -i -e 's/NTLDR/XPLDR/gi' startrom.n12
# mv startrom.n12 winxp.0

Fix XPLDR:

# cabextract winxp/i386/setupldr.ex_
# sed -i -e 's/winnt\.sif/winxp\.sif/gi' setupldr.exe
# sed -i -e 's/ntdetect\.com/ntdetect\.wxp/gi' setupldr.exe
# mv setupldr.exe xpldr
# cp winxp/i386/ntdetect.com ntdetect.wxp

Creating a remapping file

Create the file /tftproot/tftpd.remap and add the following to it:

ri ^[az]: # Remove “drive letters”
rg \\ / # Convert backslashes to slashes
rg \# @ # Convert hash marks to @ signs
rg /../ /..no../ # Convert /../ to /..no../
rg A a
rg B b
rg C c
rg D d
rg E e
rg F f
rg G g
rg H h
rg I i
rg J j
rg K k
rg L l
rg M m
rg N n
rg O o
rg P p
rg Q q
rg R r
rg S s
rg T t
rg U u
rg V v
rg W w
rg X x
rg Y y
rg Z z
r ^/(.*) \1
r ^xpldr xpldr
r ^ntdetect.wxp ntdetect.wxp
r ^winxp.sif winxp.sif

Install/Configure Samba

If you don't already have net-fs/samba installed, then:

# emerge -av net-fs/samba

Create a Samba share for your tftp server in /etc/samba/smb.conf

Note Note: Be sure you have the other required samba settings configured in the file

[Global]
interfaces = lo eth0 wlan0
bind interfaces only = yes
workgroup = WORKGROUP
security = user

[tftproot]
path = /tftproot
browsable = true
read only = yes
writable = no
guest ok = yes

Start Samba:

# /etc/init.d/samba start

or if samba has already been started:

# /etc/init.d/samba restart

Creating a Setup Instruction File

Create the file /tftproot/winxp.sif and add the following, replacing SAMBA_SERVER_IP with the local IP address of your samba server:

[data]
floppyless = "1"
msdosinitiated = "1"
; Needed for second stage
OriSrc = "\\SAMBA_SERVER_IP\tftproot\winxp\i386"
OriTyp = "4"
LocalSourceOnCD = 1
DisableAdminAccountOnDomainJoin = 1

[SetupData]
OsLoadOptions = "/fastdetect"
; Needed for first stage
SetupSourceDevice = "\Device\LanmanRedirector\SAMBA_SERVER_IP\tftproot\winxp"

[UserData]
ComputerName = *

Editing the pxelinux.cfg/default boot menu

Edit your boot menu so that it contains the following entry:

LABEL WinXP
	MENU LABEL Install MS Windows XP
	KERNEL winxp.0

Re-Start all required daemons

If the daemon isn't already running use start instead or restart in the following commands

# /etc/init.d/dnsmasq restart
# /etc/init.d/in.tftpd restart

Modify Binlsrv, update driver cache, and start driver hosting service

Change the BASEPATH= variable at or around line #62 of binlsrv.py so that it is:

# nano binlsrv.py
BASEPATH='/tftproot/winxp/i386/'

Generate driver cache:

# cd /tftproot;./infparser.py winxp/i386/

Start binlservice:

# ./binlsrv.py

Booting the client

If all is well, you should be able to boot the client choosing to boot from network in the boot options, you should get to your PXELinux bootloader, and see the Install Windows XP option after pressing enter you *should* kick off your XP installation via network!! Congratulations!