Gregory Masseau

((lambda (x) (x x)) (lambda (x) (x x)))

Saturday, March 28, 2009

Fedora NTFS initrd maker, first release.

  The first prototype of the code that will be used to produce an initrd image capable of booting off of an NTFS file system is finally ready.

What This Code Is Supposed To Do:

  This code is intended to take a standard Fedora initrd image and transform it into one capable of mounting it's root filesystem from a file located on an NTFS filesystem.

What This Code Does Today:

  Right now, the code is not complete, and does not actually produce the desired initrd image as it's final output. Rather, what is produced at this point is an environment that can be chrooted into to simulate the capabilities that will be available within the confines of the initrd image during the bootup process. This environment can be used for debugging while determining what further changes are needed to achieve our final goal.

How to Test This Code Out:
 
 To test this code out, you'll need to run it as root on a Fedora system. It should run with the standard packages provided by a base install, but you may have to add some additional entries to your path environment variable so the program can locate certain executables it needs: if a desired executable is not in your path, the program will halt and warn you of this. Simply add the directory in which it is located to your path and try again. Directions on how to test out the capabilities of the chroot environment will be provided by the program when executed. You should be able to mount the NTFS filesystem, though the ext2 filesystem cannot yet be mounted via bash as the normal mount command has not been placed in the chroot environment yet.

  The syntax you should use to invoke this code is simple: as it's first, and only argument, it expects the path of an already existing initrd image.

Get The Code:

  The current version of this program is available for download at: http://matrix.senecac.on.ca/~gjmasseau/ntfsboot/.

Wednesday, February 18, 2009

More Higher Order Python: CPS based pure I/O in Python

Continuing with my quest to achieve the purest possible I/O and state handling possible in Python, here's another experiment. This one takes a somewhat different approach than the last one, and is based on continuation passing style. The portions of the code actually written in this implementation of CPS end up looking very Lisp-ish due to the abundance of brackets, though the semantics are quite different. Anyway, on with the code...

#!/usr/bin/python

#######################################################################################################################
# Continuation passing based, functionally pure I/O in python!
# Author: Gregory Masseau.
#######################################################################################################################

# This is the main program we're going to run, stored as a thunk so we don't have to worry about what's defined. Skim
# it, and you might get some idea what we're going to do.

main = lambda:chain( (inject("Hi. Enter a string, I will repeat it twice in uppercase.\n\nEntry: ")) (prntc)(discard)
                   , (input) (mul(2))(uc) (interject((prntc("Result:"))(discard))) (prnt) (discard)
                   , (inject("\nBye.\n"))(prnt) (end("Success."))
                   )

# Now lets define all the functions we need to handle this sort of code.

#######################################################################################################################
# These functions are combinators which transform a function into a curried version of itself. This means a function that
# was previously called using syntax line 'func(x,y)' must now be called using the syntax 'func(x)(y)' to achieve the
# same effect. The advantage is that it can also be called like 'func(x)' to partially apply it, returning a function
# that recieves the remaining variables.
def curried_2args(f):             return lambda x:lambda y:                            f(x,y)
def curried_3args(f):             return lambda x:lambda y:lambda z:                   f(x,y,z)
def curried_4args(f):             return lambda x:lambda y:lambda z:lambda w:          f(x,y,z,w)
#----------------------------------------------------------------------------------------------------------------------
# These functions are combinators that modify a function (which should already be curried) to behave in a continuation
# passing style, taking the continuation as an additional argument and continuing with it (passing what would ordinarily
# be the return value) to it instaed of returning it as they ordinarily would -- remember, in this style of programming
# only the last function ever returns.
def continuationpasser_thunk(f):  return lambda c:                                     c(f())
def continuationpasser_1arg(f):   return lambda x:lambda c:                            c(f(x))
def continuationpasser_2args(f):  return lambda x:lambda y:lambda c:                   c(f(x)(y))
def continuationpasser_3args(f):  return lambda x:lambda y:lambda z:lambda c:          c(f(x)(y)(z))
def continuationpasser_4args(f):  return lambda x:lambda y:lambda z:lambda w:lambda c: c(f(x)(y)(z)(w))
#----------------------------------------------------------------------------------------------------------------------
# This turns a value into a value expecting a continuation.
def inject(x):                    return lambda c:                                     c(x)
# This evaluates it's argument and calls it's continuation without it.
def discard(x):                   return lambda c:                                     c
# This is basically shortand for (discard)(inject x).
def restart(x):                   return lambda y:lambda c:                            c(x)
# This is fun. This takes another sequence of commands in CPS format, and runs those, before passing it's argument to
# it's continuation.
def interject(f):                 return lambda x:lambda c:                            c(x) if f else c(x)
# This just ends with the exit status/message 'v', expecting no continuation.
def end(v):                       return lambda x:                                     (inject(v))(id)
# Since inject just passes it's argument to it's continuation, it can be used as a no op in CPS code blocks.
def noop(x):                      return                                               inject(x)
#----------------------------------------------------------------------------------------------------------------------
# This is kind of like (but not quite, I don't think) a monadic bind, taking a thunk and a function and returning a thunk that does the first function to the result of the thunk, returning the result of the second.
def chained(x,y):                 return lambda:                                       y(x())
# This is just the previous function extended to operate on n thunks, where 1 <>
def chain(*fs):                   return                                               reduce(chained,fs)
#----------------------------------------------------------------------------------------------------------------------
# The identity function. End a CPS function sequence with it to return a value into normal code.
def id(x):                        return                                               x
#######################################################################################################################
# These are some trivial math and I/O functions, appropriately curried and lifted to work in our CPS model.
# Adds two objects implementing +.
@continuationpasser_2args
@curried_2args
def add(x,y):                     return                                               y+x
#----------------------------------------------------------------------------------------------------------------------
# Multiplies two objects implementing *.
@continuationpasser_2args
@curried_2args
def mul(x,y):                     return                                               y*x
#----------------------------------------------------------------------------------------------------------------------
# Increments a number.
@continuationpasser_1arg
def inc(x):                       return                                               1+x
#----------------------------------------------------------------------------------------------------------------------
# Takes input from stdin.
@continuationpasser_thunk
def input():                     return                                                raw_input()
#----------------------------------------------------------------------------------------------------------------------
@continuationpasser_1arg
# Prints a value to stdout.
def prnt(s):
                                 print                                                 str(s)
                                 return                                                True
#----------------------------------------------------------------------------------------------------------------------
# Prints a value to stdout, printing no newline after.
@continuationpasser_1arg
def prntc(s):
                                 print                                                 str(s),
                                 return                                                True
#----------------------------------------------------------------------------------------------------------------------
# Returns a string in uppercase.
@continuationpasser_1arg
def uc(s):                       return                                                s.upper()
#######################################################################################################################

# Now we call main, executing our program.
main()

# Instead of calling main as above, just uncommenting this will also have a similar effect, though it's a little less
# pure since it is techincally three statements when used that way.
#(inject("Hi. Enter a string, I will repeat it twice in uppercase.\n\nEntry: "))(prntc)(discard)
#(input)(mul(2))(uc)(interject((prntc("Result:"))(discard)))(prnt)(discard)
#(inject("\nBye.\n"))(prnt)(end("Success."))

# The following is equally valid, if somewhat less readable, as well as about as pure as this gets right now.
#(inject("Hi. Enter a string, I will repeat it twice in uppercase.\n\nEntry:"))(prntc)(discard)(input)(mul(2))(uc)(interject((prntc("Result:"))(discard)))(prnt)(discard) (inject("\nBye.\n"))(prnt)(end("Success."))

Monday, February 16, 2009

Higher Order Python

Just for fun, here's an example of how one can completely ignore the bias towards a statement oriented programming style that's usually prevalent in Python and handle use I/O in a purely functional manner.

def appliedto(x): return lambda y:y(x())
def adder(x):     return lambda y:int(x)+int(y)
def l_msg(s):     return lambda:prnt(s)
def l_msgc(s):    return lambda:prntc(s)
def l_v(v):       return lambda:v
def ife(p,t,e):   return lambda x: t() if p(x) else e()
def input():      return raw_input()
def seqe(*a):     return reduce(binde,a)
def seq(*a):      return reduce(bind,a)
def binde(x,y):   return lambda:y(x())
 
def bind(x,y):
  def actionpair(*a):
    x(*a)
    return y()
  return actionpair

def passahead(x,y):
  def actionpair(*a):
    x()
    return y(*a)
  return actionpair

def prnt(s):
  print s
  return True

def prntc(s):
  print s,
  return True

hello     = l_msg("Hello!")
goodbye   = l_msg("Goodbye.")
question1 = l_msgc("Enter the first addend: ")
question2 = l_msgc("Enter the second addend:")
desc      = l_msg("Enter two numbers, and I will add them.")
smsg      = l_msgc("The sum of the numbers is ")
printnl   = l_msg("")

seq(hello
   ,printnl
   ,desc
   ,printnl
   ,question1
   ,seqe(input
        ,adder
        ,appliedto(seq(question2
                      ,input))
   ,passahead(seq(printnl
                 ,smsg)
             ,prnt))
   ,printnl
   ,goodbye
   ,printnl)()

Friday, February 13, 2009

Func Users Module version 0.5 is released.

Release 0.5, released today, consists a final polishing of the Users & Groups module before it's initial release.

Changes in this version included:

- register_method_args has been implemented in users.py
- unit tests for the methods in user.py have been added to test_client.py

As of this release, all features intended for the release version of this module are present and working, and it appears to be ready for merging.

The code is linked off the project page here.

Friday, January 30, 2009

Func Users Module v0.4 is released!

A new version of the func users & groups management module has been released for public use, testing or review. The updated module can be found here: Func Users Module v0.4.


New Features:

- Password alteration method added.
- Pluralized methods for all applicable singular methods.


Other Changes:

- General API cleanup.


Planned for version 0.5:

As nearly all core functionality for day to day user and group management is at this point complete, release 0.5 is expected to be a candidate for final release and integration with the project's main branch.

One feature remains: GECOS field manipulation methods: Currently, the GECOS field can only be manipulated as a single unit. Version 0.5 will fill in this remaining gap in functionality by providing getter/setter methods for all subfields of the GECOS field.


The updated project page is here.

Thursday, January 22, 2009

Getting the hang of Python.

So, I've been practicing a little more with Python, and kind of think I'm getting the hang of it.

But as far as the language's supposed 'readability', I offer the following counterexample...

AccessTable.py
# Usage: head -60 /var/log/apache2/access.log | python AccessTable.py
# Effect: Produces a spiffy HTML page containing the contents of your Apache access log in a table.

from fileinput import input as OO
O=[(lambda o,oo,ooo:[o]if(oo=="")else[o+oo[0],oo[1:]]if(oo[0]==ooo)else(O[0](o+oo[0],oo[1:],ooo))),(lambda o,oo:[o]if(((O[0]("",o,oo[0])if(not(o==""or(oo==[])))else[o,""])[0]and(not(O[0]("",o,oo[0])if(not(o==""or(oo==[])))else[o,""])[1]))or(o==""))else[(O[0]("",o,oo[0])if(not(o==""or(oo==[])))else[o,""])[0]]+[(O[0]("",o,oo[0])if(not(o==""or(oo==[])))else[o,""])[1]]if(not(oo[1:]))else[(O[0]("",o,oo[0])if(not(o==""or(oo==[])))else[o,""])[0]]+O[1]((O[0]("",o,oo[0])if(not(o==""or(oo==[])))else[o,""])[1],oo[1:])),""+chr(60)+"/b"+chr(62)+""+chr(60)+"/u"+chr(62)+"",(lambda o,oo:""if(oo=="")else(oo[0])if((oo[0]!=o)and(not(oo[1:])))else(oo)if(oo[0]!=o)else(O[3](o,oo[1:]))),(lambda o,oo:""if(oo=="")else(oo[0])if((not(oo[1:])))else(O[3](o,(oo)if(oo[-1]!=o)else(O[4](o,oo[:-1]))))),["IP Address","Date","Time","Method","URL","Protocol Version","Error Code","Bytes","URL 2","Client"],(lambda o:""+chr(60)+"html"+chr(62)+"\n\t"+chr(60)+"body"+chr(62)+"\n"+'\t\t'+chr(60)+'table border="1"'+chr(62)+"\n"+"\n".join(["\t\t\t"+chr(60)+"tr"+chr(62)+"\n"+line+"\t\t\t"+chr(60)+"/tr"+chr(62)+""for(line)in[''.join(o)for(o)in[["\t\t\t\t"+chr(60)+"td"+chr(62)+""+word+""+chr(60)+"/td"+chr(62)+"\n"for(word)in(line)]for(line)in(o)]]])+"\n\t\t"+chr(60)+"/table"+chr(62)+"\n"+"\t"+chr(60)+"/body"+chr(62)+"\n"+chr(60)+"/html"+chr(62)+""),""+chr(60)+"b"+chr(62)+""+chr(60)+"u"+chr(62)+"",(lambda s:[(o)for(o)in[(lambda o:O[4]("\n",O[4](":",O[4]("]",O[4]('"',O[4](" ",o))))))(o)for(o)in(O[1](s,[" ","[",":","]",'"'," "," ",'"'," "," "," "," "]))]if(o)not in[" ",'"',"","- - ["]])]
print(O[6]([[O[7]+o+O[2]for(o)in(O[5])]]+[O[8](o)for(o)in(OO())]))





Just a little something I came up with this evening. Feel free to try it out - it works with the default log format in the version of Apache installed on my (somewhat outdated) Ubuntu 6.06 webserver. If the format gets messed up in the blog, a copy is on the web at 'http://matrix.senecac.on.ca/~gjmasseau/AccessTable.py'.

Tuesday, January 20, 2009

Observations on the installation of FreeBSD

Differences in installation between FreeBSD and Linux:

During installation the differences between FreeBSD and Linux are not particularily pronounced: the installer's interface and usage bear quite a significant resemblence to those used in many Linux distributions, Debian and Slackware being two particularly notable examples. While the overall experience is quite similar to installing one of these distributions of Linux, there are a few particular areas that are clearly a little bit different.

The first difference one is likely to notice is that the FreeBSD version of the fdisk utility uses some terminology that may be unfamiliar - instead of referring to primary partitions, it refers to slices - in fact, they are the same thing, and merely the terminology has been changed. FreeBSD requires one slice on which to be installed. Meanwhile, after the boot manager has been installed, the FreeBSD DiskLabel Editor will launch, and you may notice that the word 'parititons' has been repurposed - in FreeBSD, the word 'partition' is used not to refer to physical disk partitions , but rather refers to an additional layer of storage abstraction implemented on top of the physical slices on may create on their storage devices (e.g., harddrives, flash media, etc). Many configuration files found in /etc look quite similar to their Linux counterparts, such as fstab, while a few, such as freebsd-update.conf, are clearly new. Additionally, the structure of the rc files is significantly different, with all startup script code contained in a small set of rc.* files located in the /etc/ directory itself, rather than a distinct folder for each level -- indeed, runlevels themselves are absent!

Things I liked about the FreeBSD installer:

The installation experience was simple, to the point, and straightforwards, while providing a fairly wide set of options to customize your installation. The straightforwards, simple user interface was refreshingly uncluttered compared to the GUI installers that have grown popular in some distributions, and I must confess it elicited some nostalgia with the memory of installing Slackware many times (though never more than once on a given machine! How's that for stable?) back in the good old days.

Things I did not like about the FreeBSD installer:

So far, I haven't really found anything to dislike - maybe something will come up later on, during use, but I have no issues with the installer.