newspaint

Documenting Problems That Were Difficult To Find The Answer To

Monthly Archives: Jun 2016

Creating a Basic CGI Executable Using Rust

I created a new cargo project called “cgitest”:

~$ cargo new cgitest --bin
~$ cd cgitest
~/cgitest$

Then I added the following Rust code into src/main.rs:

// Use the following as a guide:
//   http://httpd.apache.org/docs/current/howto/cgi.html

use std::io::Write;
use std::env;
use std::collections::btree_map::BTreeMap;

fn write_stderr( msg : String ) {
    let mut stderr = std::io::stderr();
    write!(&mut stderr, "{}", msg).unwrap();
}

fn write_stderr_s( msg : &str ) {
    write_stderr( msg.to_string() );
}

fn write_stdout( msg : String ) {
    let mut stdout = std::io::stdout();
    write!(&mut stdout, "{}", msg).unwrap();
}

fn write_stdout_s( msg : &str ) {
    write_stdout( msg.to_string() );
}

fn html_escape( msg : String ) -> String {
    let mut copy : String = String::with_capacity( msg.len() );

    for thechar in msg.chars() {
        if thechar == '&' {
            copy.push_str( "&" );
        } else if thechar == '<' {
            copy.push_str( "&lt;" );
        } else if thechar == '>' {
            copy.push_str( "&gt;" );
        } else if thechar == '\"' {
            copy.push_str( "&quot;" );
        } else {
            copy.push( thechar );
        }
    }

    return copy;
}

fn main() {
    write_stdout_s( "Content-type: text/html\n" );
    write_stdout_s( "\n" );
    write_stdout_s( "<html>\n" );
    write_stdout_s( "  <head>\n" );
    write_stdout_s( "    <title>Rust CGI Test</title>\n" );
    write_stdout_s( "    <style type=\"text/css\">\n" );
    write_stdout_s( "      td { border:1px solid black; }\n" );
    write_stdout_s( "      td { font-family:monospace; }\n" );
    write_stdout_s( "      table { border-collapse:collapse; }\n" );
    write_stdout_s( "    </style>\n" );
    write_stdout_s( "  </head>\n" );
    write_stdout_s( "  <body>\n" );
    write_stdout_s( "    <h1>Environment</h1>\n" );
    write_stdout_s( "    <table>\n" );
    write_stdout_s( "      <tr><th>Key</th><th>Value</th></tr>\n" );

    // copy environment into a BTreeMap which is sorted
    let mut sortedmap : BTreeMap<String,String> = BTreeMap::new();
    for (key, value) in env::vars() {
        sortedmap.insert( key, value );
    }

    // output environment into HTML table
    for (key, value) in sortedmap {
        write_stdout(
            format!(
                "      <tr><td>{}</td><td>{}</td></tr>\n",
                html_escape( key ),
                html_escape( value )
            )
        );
    }
    write_stdout_s( "    </table>\n" );
    write_stdout_s( "  </body>\n" );
    write_stdout_s( "</html>\n" );
}

Compiling it using the cargo build --release command produced a binary in target/release/cgitest which can be launched from Apache as a CGI script.

Where Is The Std Crate Located In A Rust Installation

I downloaded Rust (the programming language) from the Rust downloads page. Specifically I downloaded the 64-bit Linux .tar.gz file and then extracted it to /opt/ on my filesystem and symlinked /opt/rust to the untarred directory.

However when I went to compile a test Rust program I got the following error:

$ /opt/rust/rustc/bin/rustc test.rs
error: can't find crate for `std` [E0463]
error: aborting due to previous error

I searched for the std crate by running:

$ find /opt/rust/ -name 'libstd*'
/opt/rust/rustc/lib/libstd-d16b8f0e.so
/opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d16b8f0e.so
/opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d16b8f0e.rlib
/opt/rust/rust-docs/share/doc/rust/html/src/std/up/src/libstd

I tried then compiling my Rust program using the first path, “/opt/rust/rustc/lib/“:

$ /opt/rust/rustc/bin/rustc -L /opt/rust/rustc/lib test.rs
error:error: can't find crate for `core` which `std` depends on [E0463]
error:error: aborting due to previous error

So, where is libcore?

$ find /opt/rust/ -name 'libcore*'
/opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-d16b8f0e.rlib
/opt/rust/rust-docs/share/doc/rust/html/src/core/up/src/libcore

I then tried compiling using the path to libcore.

$ /opt/rust/rustc/bin/rustc -L /opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib test.rs
$

Success!

If you want to pass command line options for rustc to cargo you can do it as follows:

$ RUSTFLAGS="-L /opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" cargo
$

Lenovo TS-140 Ethernet Card Halt

I had my Ethernet interface effectively just die after 33 days uptime in Linux and running continuously for many, many months.

What was particularly bizarre was that I had an identical Lenovo TS-140 running beside it attached to the same Ethernet switch – that was running a GUI and it completely froze at this point. At least with the first console server I was able to access it and make a copy of the logs for later analysis after rebooting.

From /var/log/dmesg I had the following:

[2931914.307645] ------------[ cut here ]------------
[2931914.307663] WARNING: CPU: 0 PID: 0 at /build/linux-Mxzr_W/linux-3.13.0/net/sched/sch_generic.c:264 dev_watchdog+0x276/0x280()
[2931914.307668] NETDEV WATCHDOG: eth0 (e1000e): transmit queue 0 timed out
[2931914.307671] Modules linked in: btrfs raid6_pq xor ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs libcrc32c nf_conntrack_netlink nfnetlink_queue nfnetlink_log nfnetlink bluetooth xt_LOG xt_limit ts_bm xt_comment xt_string xt_conntrack xt_HL xt_nat veth xt_CHECKSUM iptable_mangle ipt_MASQUERADE iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 xt_tcpudp bridge stp llc iptable_filter ip_tables x_tables x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec kvm snd_hwdep snd_pcm mei_me snd_page_alloc serio_raw snd_timer mei snd shpchp lpc_ich soundcore mac_hid nf_nat_sip nf_conntrack_sip nf_nat nf_conntrack zfs(POX) zunicode(POX) zcommon(POX) znvpair(POX) spl(OX) zavl(POX) hid_generic usbhid hid dm_crypt usb_storage crct10dif_pclmul crc32_pclmul i915 aesni_intel aes_x86_64 lrw e1000e gf128mul psmouse glue_helper ablk_helper i2c_algo_bit cryptd ptp drm_kms_helper pps_core drm ahci libahci video wmi
[2931914.307793] CPU: 0 PID: 0 Comm: swapper/0 Tainted: P           OX 3.13.0-85-generic #129-Ubuntu
[2931914.307797] Hardware name: LENOVO ThinkServer TS140/ThinkServer TS140, BIOS FBKT82AUS 04/02/2014
[2931914.307800]  0000000000000000 ffff88051ea03d98 ffffffff8172b6a7 ffff88051ea03de0
[2931914.307808]  0000000000000009 ffff88051ea03dd0 ffffffff810699cd 0000000000000000
[2931914.307814]  ffff8800361a0000 ffff8804fc73e880 0000000000000001 0000000000000000
[2931914.307820] Call Trace:
[2931914.307824]  <IRQ>  [<ffffffff8172b6a7>] dump_stack+0x64/0x82
[2931914.307845]  [<ffffffff810699cd>] warn_slowpath_common+0x7d/0xa0
[2931914.307851]  [<ffffffff81069a3c>] warn_slowpath_fmt+0x4c/0x50
[2931914.307863]  [<ffffffff8164ef86>] dev_watchdog+0x276/0x280
[2931914.307870]  [<ffffffff8164ed10>] ? dev_graft_qdisc+0x80/0x80
[2931914.307878]  [<ffffffff81076956>] call_timer_fn+0x36/0x150
[2931914.307884]  [<ffffffff8164ed10>] ? dev_graft_qdisc+0x80/0x80
[2931914.307892]  [<ffffffff8107798f>] run_timer_softirq+0x21f/0x310
[2931914.307900]  [<ffffffff8106f00c>] __do_softirq+0xfc/0x310
[2931914.307908]  [<ffffffff8106f595>] irq_exit+0x105/0x110
[2931914.307919]  [<ffffffff8173e755>] smp_apic_timer_interrupt+0x45/0x60
[2931914.307926]  [<ffffffff8173d0dd>] apic_timer_interrupt+0x6d/0x80
[2931914.307929]  <EOI>  [<ffffffff815dc5e2>] ? cpuidle_enter_state+0x52/0xc0
[2931914.307946]  [<ffffffff815dc5d8>] ? cpuidle_enter_state+0x48/0xc0
[2931914.307954]  [<ffffffff815dc72c>] cpuidle_idle_call+0xdc/0x220
[2931914.307963]  [<ffffffff8101e4de>] arch_cpu_idle+0xe/0x30
[2931914.307971]  [<ffffffff810c1eb5>] cpu_startup_entry+0xc5/0x2b0
[2931914.307980]  [<ffffffff81719777>] rest_init+0x77/0x80
[2931914.307990]  [<ffffffff81d34f70>] start_kernel+0x438/0x443
[2931914.307998]  [<ffffffff81d34941>] ? repair_env_string+0x5c/0x5c
[2931914.308006]  [<ffffffff81d34120>] ? early_idt_handler_array+0x120/0x120
[2931914.308014]  [<ffffffff81d345ee>] x86_64_start_reservations+0x2a/0x2c
[2931914.308021]  [<ffffffff81d34733>] x86_64_start_kernel+0x143/0x152
[2931914.308026] ---[ end trace 7c85c7d5a955f5e4 ]---
[2931914.308063] e1000e 0000:00:19.0 eth0: Reset adapter unexpectedly
[2931918.468625] e1000e: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: Rx/Tx
[2931938.327046] e1000e 0000:00:19.0 eth0: Reset adapter unexpectedly
[2931942.327873] e1000e: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: Rx/Tx

Almost exactly the same set of messages described in this bug thread (but with no solution at time of writing).

A few solutions were proposed. This one proposed disabling TSO, GSO and GRO using ethtool:

ethtool -K eth0 gso off gro off tso off

But I decided to try turning active power state management off in the kernel after seeing the following in /var/log/dmesg:

[    0.114082] ACPI FADT declares the system doesn't support PCIe ASPM, so disable it
[    0.147241] acpi PNP0A08:00: _OSC: OS supports [ExtendedConfig ASPM ClockPM Segments MSI]
[    0.147621] acpi PNP0A08:00: FADT indicates ASPM is unsupported, using BIOS configuration

So I followed the recommendation in this post by adding pcie_aspm=off to /etc/default/grub as follows:

GRUB_CMDLINE_LINUX_DEFAULT="pcie_aspm=off nosplash"

… and then re-ran sudo update-grub.

Note that I cannot tell you if this definitively works. This Ethernet crash only happened once in the 14 months I’ve had the server. Hopefully it won’t happen again.

Audacious on Ubuntu Doesn’t Play the Next Song in the Playlist

Found that Audacious only plays one song and then stops?

According to this bug report Audacious disables playlist advance if you press the ctrl+N toggle.

Sometimes I think my Firefox session has the focus and I press ctrl+N for a new window when, in fact, Audacious was the last window I had focus in – which trips up this issue.

You can edit the ~/.config/audacious/config file and change:

[audacious]
no_playlist_advance=TRUE

into:

[audacious]
no_playlist_advance=FALSE