Disable console bell in FreeBSD

I use Bash and frequently utilize tab completion. On my FreeBSD, when there are multiple options during tab completion, the annoying console bell rings. For C programmers, it is the ‘\a’ that you included in your printf() calls when first learning C to drive others crazy.

To disable it, as root user you can run:

# sysctl hw.syscons.bell=0
hw.syscons.bel;: 1-> 0

Add that command to /etc/sysctl.conf to permanently disable it.  Good riddance!

Erlang Programming Exercise 12-3: The Database Server as an Application

First create an OTP Application directory structure. The work flow resembles something like the following if you’re on UNIX.

cd ~/work/erlang
mkdir ~/work/erlang/chapter12/{src,ebin,include,priv}
cp db_server_otp.erl db_server_sup.erl ~/work/erlang/chapter12/src
cd ~/work/erlang/chapter12/src
erlc *.erl
mv *.beam ../ebin

With the source code and BEAM files ready, now create an app file, db_server_app.erl:

-module(db_server_app).
-export([start/2,stop/1]).
-behavior(application).

start(_Type, _StartArgs) ->
    db_server_sup:start().

stop(_State) ->
    ok.

Compile this code and then move the BEAM file to the ebin folder. Create an application resource file describing the application, db_server.app in the ebin folder:

{application,
 db_server,
 [{description, "Erlang Prgramming Ch. 12 DB Server"},
  {vsn, "1.0"},
  {modules, [db_server_otp, db_server_sup, db_server_app]},
  {registered, [db_server_sup]},
  {applications, [kernel, stdlib]},
  {env, []},
  {mod, {db_server_app, []}}
 ]
}.

The final directory structure should look like this:

~/work/erlang/chapter12$ ls -1
ebin
include
priv
src
~/work/erlang/chapter12$ ls -1 ebin
db_server.app
db_server_app.beam
db_server_otp.beam
db_server_sup.beam
~/work/erlang/chapter12$ ls -1 src
db_server_app.erl
db_server_otp.erl
db_server_sup.erl

With the BEAM files and app files in the ebin directory, the application can now be tested with the Erlang shell.

Erlang R13B03 (erts-5.7.4)  [64-bit] [smp:8:2] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.4  (abort with ^G)
1> code:add_path("/home/bryan/work/erlang/chapter12/ebin").
true
2> application:start(db_server).
ok
3> db_server_otp:write("Ted", "7").
ok
4> db_server_otp:read("Ted").
{ok,"7"}
5> application:stop(db_server).
ok

=INFO REPORT==== 3-Nov-2011::16:32:08 ===
    application: db_server
    exited: stopped
    type: temporary
6> whereis(db_server_sup).
undefined

Success! (Note: this was much easier than the first time I tried to get a Tomcat servlet working…)

Erlang Proramming Exercise 12-2: Supervising the Database Server


-module(db_server_sup).
-export([start/0,init/1]).
-behavior(supervisor).

start() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init(_Arguments) ->
    DbServerOtp = {db_server_otp,                %% Id
                   {db_server_otp, start, []},   %% child process
                   permanent,                    %% restart
                   30000,                        %% shutdown (ms)
                   worker,                       %% type
                   [db_server_otp]},             %% required modules
    {ok,
     {{one_for_all,           %% terminate all children and restart
       5,                     %% max of n restarts in MaxSeconds
       3600},                 %% MaxSeconds (s)
      [DbServerOtp]}}.        %% child process list

EP Exercise 12-1: Database Server Revisited

-module(db_server_otp).
-export([start/0,stop/0]).
-export([write/2,read/1,delete/1,match/1]).
-export([init/1,terminate/2,handle_cast/2,handle_call/3]).
-behavior(gen_server).

%%
%% Operations & Maintenance API
%%

start() ->
    gen_server:start({local, ?MODULE}, ?MODULE, [], []).

stop() ->
    gen_server:cast(?MODULE, stop).

%%
%% DB Server API
%%

write(Key, Data) ->
    gen_server:call(?MODULE, {write, Key, Data}).

read(Key) ->
    gen_server:call(?MODULE, {read, Key}).

delete(Key) ->
    gen_server:call(?MODULE, {delete, Key}).

match(Element) ->
    gen_server:call(?MODULE, {match, Element}).

%%
%% OTP gen_server Callback Functions
%%

init(_Arguments) ->
    {ok, []}.

terminate(_Reason, _LoopData) ->
    ok.

handle_cast(stop, LoopData) ->
    {stop, normal, LoopData}.

handle_call({write, Key, Data}, _From, LoopData) ->
    case lists:keymember(Key, 1, LoopData) of
        true ->
            NewLoopData = lists:keyreplace(Key, 1, LoopData, {Key, Data}),
            Reply = ok;
        false ->
            NewLoopData = LoopData ++ [{Key, Data}],
            Reply = ok
    end,
    {reply, Reply, NewLoopData};
handle_call({read, Key}, _From, LoopData) ->
    case lists:keymember(Key, 1, LoopData) of
        true ->
            {_, Value} = lists:keyfind(Key, 1, LoopData),
            Reply = {ok, Value};
        false ->
            Reply = {error, instance}
    end,
    {reply, Reply, LoopData};

handle_call({delete, Key}, _From, LoopData) ->
    case lists:keymember(Key, 1, LoopData) of
        true ->
            NewLoopData = lists:keydelete(Key, 1, LoopData),
            Reply = ok;
        false ->
            NewLoopData = LoopData,
            Reply = ok
    end,
    {reply, Reply, NewLoopData};

handle_call({match, Element}, _From, LoopData) ->
    Matches = lists:filter(
                fun({_ ,Value}) ->
                  if
                     Value =:= Element -> true;
                     true -> false
                  end end,
                LoopData),
   Reply = get_db_keys(Matches, []),
   {reply, Reply, LoopData}.

get_db_keys([], KeyList) -> KeyList;
get_db_keys(ListOfTuples, KeyList) ->
    [H|T] = ListOfTuples,
    {Key, _} = H,
    get_db_keys(T, KeyList ++ [Key]).

EP Exercise 5-1: A Database Server


-module(db_server).
-export([start/0,stop/0,upgrade/1,code_upgrade/0]).
-export([write/2,read/1,delete/1]).
-export([init/0,loop/1]).
-vsn(1.0).

start() ->
    register(deb_server, spawn(db_server, init, [])).

stop() ->
    db_server ! stop.

upgrade(Data) ->
    db_server ! {upgrade, Data}.

write(Key, Data) ->
    db_server ! {write, Key, Data}.

read(Key) ->
    db_server ! {read, self(), Key},
    receive Reply ->
             Reply end.

delete(Key) ->
    db_server ! {delete, Key}.

code_upgrade(Data) ->
    db_server ! {code_upgrade, Data}.

init() ->
    loop(db:new()).

loop(Db) ->
    receive
        {write, Key, Data} ->
            loop(db:write(Key, Data, Db));
        {read, Pid, Key} ->
            Pid ! db:read(Key, Db),
            loop(Db);
        {delete, Key} ->
            loop(db:delete(Key, Db));
        {upgrade, Data} ->
            NewDb = db:convert(Data, Db),
            db_server:loop(NewDb);
        code_upgrade ->
            loop(db:code_upgrade(Data));
        stop ->
            db:destroy(Db)
    end.

EP Exercise 4-2: The Process Ring

My solution for Exercise 4-2 in the book Erlang Programming

%%
%% Erlang Programming Exercise 4-2
%%

-module(ring).
-export([start/3,create_node/3,stop/0]).

create_node(M,N,Msg) ->
    io:format("Creating node ~w (~w)~n", [N,self()]),
    if
        N-1 > 0  -> NextPid = spawn(ring,create_node,[M,N-1,Msg]);
        N-1 == 0 -> NextPid = head
    end,
    print_m_times(NextPid,N,Msg,M),
    loop(NextPid).

start(M, N, Msg) ->
    io:format("Spawning ~w nodes!~n",[N]),
    Pid = spawn(ring,create_node,[M,N,Msg]),
    register(head, Pid),
    ok. 

stop() ->
    head ! quit,
    ok. 

loop(NextPid) ->
    receive
        {print, Pid, NodeNum, MsgContents} when Pid /= self() ->
            io:format("(~w) msg from node ~w: ~s~n",[self(),NodeNum,MsgContents]),
            NextPid ! {print, Pid, NodeNum, MsgContents},
            loop(NextPid);
        quit ->
            NextPid ! quit,
            io:format("Destroying node (~w)~n", [self()]),
            true
    end.

print_m_times(_,_,_,0) ->
    true;
print_m_times(NextPid,FromNode,Msg,M_Times) ->
    NextPid ! {print, self(), FromNode, Msg},
    print_m_times(NextPid,FromNode,Msg,M_Times-1).

EP Exercise 4-1: An Echo Server

My solution for Exercise 4-1 in the book Erlang Programming.

%%
%% Erlang Programming Exercise 4-1
%%

-module(echo).
-export([start/0,print/1,stop/0,loop/0]).

start() ->
    %% function specified in spawn/3 must be exported !!
    Pid = spawn(echo, loop, []),
    register(echo_server, Pid),
    ok. 

stop() ->
    echo_server ! stop,
    ok. 

print(Term) ->
    echo_server ! {print, Term},
    ok. 

loop() ->
    receive
        {print, Msg} -> io:format("~s~n",[Msg]),
                        loop();
        stop -> true
    end.

WindowMaker as the X11 window manager

My light-weight window manager of choice is WindowMaker.  It is simple, easy to modify, and stays out of the way.  The default window manager installed with X11 on FreeBSD, however, is twm.  I first experienced twm in the Virginia Tech Computer Science Dept. UNIX lab (all FreeBSD boxes), and tvm looks exactly the same today.  I cannot pick on it too much, however.  The guy in the office next door to me at work uses tvm on his Linux box.  I suppose I ought to call it an Emacs box, since he does everything out of emacs.  I digress…

Please read this excellent tutorial on xinit and .xinitrc files from the Fluxbox project first.  The tutorial explains very clearly how the xinit program works and how .xinitrc files are processed.  In short, however, once the end of .xinitrc is reached, X11 is shutdown.  Thus you need a blocking command in xinitrc scripts that prevents the script from exiting.  In the default xinitrc script,  /usr/X11R6/lib/X11/xinit/xinitrc, I noticed towards the bottom of the script:

twm &

It was followed by three xterm commands. The first two were also run in the background, but the final xterm was not run in the background, thus preventing X11 from terminating until that terminal is closed by the user.  No more twm on this box though!  I removed the xterm commands, and changed the twm line to the following:

wmaker

Now, WindowMaker is launched and until the user exits the WindowMaker session X11 will continue to run. All users on my FreeBSD will have WindowMaker when the execute startx.  I also created a .xinitrc in my user account home directory as follows:

exec wmaker

In reality, however, I have XDM to run as my “magic client” (see article linked above). Instead of managing a separate .xinitrc and .xsession file, I just symlinked the files together so that any changes are available in both files, in the cast that I ever disable XDM.

ln -s .xinitrc .xsession

After I log into the system via XDM, my .xsession file is executed and WindowMaker is launched.

Setting up XDM

The X Display Manager, or XDM, is a program that allows one to log into a system using a GUI program.  Rather than logging into a system and then manually starting X, X comes up after boot and is ready to go.  While XDM (or GDM for GNOME or KDM for KDE) is not necessary on server systems, any system where X Windows is used on a regular basis benefits from XDM.  And XDM is easy to set up too.  With FreeBSD, one can simply build and install from the ports collections:

cd /usr/ports/x11/xdm
make install clean

Now one just needs to modify /etc/ttys to enable XDM. The XDM entry is already in this file, it is just disabled on the default install. To enable XDM after installing it, change “off” to “on” between the xterm and secure parameters.

ttyv8 "/usr/local/bin/xdm -nodaemon" xterm on secure"

Unlike GDM or KDM, XDM does not allow one to select a window manager. The window manager should be executed from a .xsession script in your home directory. I setup my system so that .xsession is a symlink to a .xinitrc file (read by startx when manually starting X11) in my home directory. If you need XDM and startx to have different startup methods, then you must provide separate files with customization for each program.

Without a .xsession file, XDM and startx default to /usr/X11R6/lib/X11/xinit/xinitrc. With my default install of FreeBSD, at the bottom of the script, the window manager twm is started, along with three xterms which are opened by default.

I cannot stand twm, so next I will look at setting up a different light-weight window manager. As my experience with Ubuntu and GNOME on this machine proved, I don’t have the memory on this machine for desktop environments like GNOME or KDE.

nVidia graphics driver on FreeBSD 8.2

First of all, find the proper driver for your device.  I used nVidia’s driver download page to get the right version: 96.43.20.  My card is an nVidia GeForce4 MX 420, and it is not supported on higher version number drivers that support more modern video cards.

Download the driver tarball with your web brower or wget and unarchive it.

cd /root
tar -xzf NVIDIA-FreeBSD-x86-96.43.20
cd  /root/NVIDIA-FreeBSD-x86-96.43.20
vi doc/README

As you can see in the documentation, you just need to do a ‘make install’.  Before doing so, however, comment out lines 25 through 36 as this check will prevent you from being able to build the driver.  (I don’t know why this check was in here…perhaps on more modern drivers this is not necessary)

/*
#if __FreeBSD_version >= 800000
#error This driver does not support FreeBSD 8.x/-CURRENT!
#endif
#if __FreeBSD_version >= 700000 && __FreeBSD_version < 700055 #error This driver does not support FreeBSD 7.x/-CURRENT! #endif #if __FreeBSD_version >= 600000 && __FreeBSD_version < 600034
#error This driver does not support FreeBSD 6.x/-CURRENT!
#endif
#if __FreeBSD_version < 503000
#error This driver requires FreeBSD 5.3 or later!
#endif
*/

Build and install the driver:

make install

If the driver builds with no errors, the driver kernel module should be installed in /boot/modules.  To test the driver and make sure that everything works,

I used the nvidia-xconfig tool to create a basic xorg.conf file. The tool automatically detected my video card and setup the correct information in the Device section.

Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
    BoardName      "NV17 [GeForce4 MX 420]"
    BusID          "PCI:1:0:0"
EndSection

The tool also added additional required modules by the driver.

Section "Module"
	Load  "dbe"
	Load  "dri"
	Load  "dri2"
	Load  "extmod"
	Load  "glx"
	Load  "record"
EndSection

I then had to customize the monitor settings. I have a wide-screen monitor that I like to run at 1920×1200. I tried explicitly setting this in the Modes subsection of the Screen section, but was unable to get the setting to work (though 1024×768 worked with no problems). Apparently, X is smart enough these days to figure out the max resolution on its own, so I simply commented out the Modes subsection.

Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    SubSection     "Display"
        Depth       24
#        Modes      "1920x1200" "1024x768" "800x600" "640x480"
    EndSubSection
EndSection

I setup the Monitor section with more descriptive names as well as putting in the exact horizontal sync rate and vertical refresh rate from the instruction manual for my Samsung display.

Section "Monitor"
    Identifier     "Monitor0"
    VendorName     "Samsung"
    ModelName      "Syncmaster P2250"
    HorizSync       30.0 - 81.0
    VertRefresh     56.0 - 60.0
    Option         "DPMS"
EndSection

To test the configuration, use the -config option on the X program, passing it the customized X configuration.

X -config /root/xorg.nvidia.conf

Once satisfied with the settings, I copied the config file to /etc/X11/xorg.conf and tried to start X Windows.

cp /root/xorg.nvidia.conf /etc/X11/xorg.conf
startx   # ugly tvm should start

Finally, with the driver working, it can be added to load automatically during boot, allowing the use of graphical log-in programs such as XDM.  To load the driver during the boot stage, add the following to /boot/loader.conf:

nvidia_load="YES"

Next I shall look at configuring XDM so that I don’t have to always manually start X.

Follow

Get every new post delivered to your Inbox.