The Blog of Tom Webster

Chronic Ranter, Reviewer, and Developer. I speak only for myself, opinions are my own.

Installing and Holding Stable Packages in Debian Sid

  2016-01-22 15:49:13 PST

Sometimes, running Debian Unstable is... well... unstable. Most of the time it's perfectly stable, it's just bleeding-edge Debian, perfect for my workstations at home, where I want the latest and greatest the FOSS community has to offer. Rarely, a package will just break or come with some nasty bugs. Two I've gotten bit by recently are network-manager and nvidia-driver. These have been fixed recently, but for a bit, the network-manager bug really bummed me out, I wanted a solution to get back to 'normal' (and I had already cleared my apt-cache).

In both cases, I was able to install the package from stable or testing and get back to my original functionality. Today I'll walk you through how to do that.

First, let's make sure we have the ability to use HTTPS with apt:

sudo apt-get install apt-transport-https

I use the https mirrors at kernel.org, so my /etc/apt/sources.list looks like this:

deb https://mirrors.kernel.org/debian/ sid main contrib non-free
deb-src https://mirrors.kernel.org/debian/ sid main contrib non-free
deb https://mirrors.kernel.org/debian/ testing main contrib non-free
deb-src https://mirrors.kernel.org/debian/ testing main contrib non-free
deb https://mirrors.kernel.org/debian/ stable main contrib non-free
deb-src https://mirrors.kernel.org/debian/ stable main contrib non-free

Next, let's set our default release. This will tell apt where we prefer our packages to come from. In my case, I want my packages to come from sid (the codename for Debian unstable).

Add this line to /etc/apt/apt.conf.d/70debconf:

APT::Default-Release "sid";

Note: If you want your default release to be stable or testing, use that instead of sid in the line above.

What this does is tell apt and dpkg that we prefer for our packages to come from the sid release channel, that keeps us on the unstable branch of Debian. Nice and current. To see this in action, run this command:

sudo apt-cache policy network-manager

network-manager:
  Installed: 0.9.10.0-7
  Candidate: 1.0.10-2
  Version table:
    1.0.10-2 990
      990 https://mirrors.kernel.org/debian sid/main amd64 Packages
    1.0.10-1 500
      500 https://mirrors.kernel.org/debian testing/main amd64 Packages
    *** 0.9.10.0-7 500
      500 https://mirrors.kernel.org/debian stable/main amd64 Packages
      100 /var/lib/dpkg/status

See the 990 next to the sid version? That's our pin-priority value, the highest value wins when apt-get looks for a version to install. By setting our default release channel, we've set sid's pin-priority to 990.

For more information on pinning, check out these great resources:

You can now use -t stable to install a package from the stable repositories:

sudo apt-get install -t stable network-manager

Now, that package will be upgraded next time you run updates (even unattended-upgrades will do this), so you need to tell dpkg to hold the package and add it to the "Don't auto-upgrade this one" list:

If you have unattended-upgrades installed and configured, you should see this section in /etc/apt/apt.conf.d/50unattended-upgrades:

// List of packages to not update (regexp are supported)
Unattended-Upgrade::Package-Blacklist {
//      "vim";
//      "libc6";
//      "libc6-dev";
//      "libc6-i686";
};

Add your package to that list:

// List of packages to not update (regexp are supported)
Unattended-Upgrade::Package-Blacklist {
//      "vim";
//      "libc6";
//      "libc6-dev";
//      "libc6-i686";
        "network-manager";
};

Now unattended-upgrades won't upgrade that package, but you still can accidentally upgrade it if you use sudo apt-get upgrade or sudo apt-get dist-upgrade, so here's how to fix that problem:

Run: echo "network-manager hold" | sudo dpkg --set-selections

Note: You don't want to leave packages on hold forever, that would be very very bad. Packages regularly get security updates, and even the bug you suffer from currently will eventually be fixed (watch the Debian bug tracker, it's helpful), so you'll want to remove the hold once a new version of the package has been released. If you keep a package on hold forever, you will compromise the security of your system!

To "unhold" a package, use this command:

echo "network-manager install" | sudo dpkg --set-selections

Now you can sudo apt-get upgrade or sudo apt-get dist-upgrade to get the latest release of the package.

If you have any questions or comments, hit up the section below.

How to Change Date in a Git Commit

  2016-01-21 03:50:18 PST

Sometimes you just gotta fix a date in git commits, and this can happen for a wide variety of reasons. Maybe you were on a system with an unset clock and you want accurate timekeeping, maybe you don't want to admit you were up at 4AM coding. I get it. Here's the fix:

git filter-branch --env-filter \
'if [ $GIT_COMMIT = 119f9ecf58069b265ab22f1f97d2b648faf932e0 ]; then
export GIT_AUTHOR_DATE="Fri Jan 2 21:38:53 2009 -0800"
export GIT_COMMITTER_DATE="Sat May 19 01:01:01 2007 -0700"
fi'

Passphrases

  2016-01-05 01:13:00 PST

Passwords are so last year

Passphrases are the new hotness. Who cares about upper case, lower case, symbols, and numbers? Not me.

Caveats:

Time to crack is based on a massive cracking array that runs one hundred trillion guesses per second. (Thanks to GRCs password haystacks page for the calculations)

Take this password, typical, classical: tha2uy2Ieti+

And this one, a bit longer: ae3chav3Ho{cik6g

Let's get crazy: pahzoon2uCh9phoS'iSeeBa

And this passphrase: unlock syntax for tailspin

And this passphrase, but two words longer: unlock syntax for massive director tailspin

The evidence is clear, the four-word passphrase is not only easier to remember, but it's even more secure than the 23-character all-random password. Let's keep this in mind when choosing a new root passphrase.

Storing the passphrase

You should be using a password manager by now. Also, if you're storing the passphrases securely, why not make a 64-character random password for everything? Use a nice passphrase as your master password.

Startup Apps in Gnome 3

  2016-01-04 02:13:06 PST

I recently switched to Gnome 3 on my personal laptop. When Gnome 3 first launched, it was an utter train wreck. Completely unusable, poor design choices, and seemingly purposely-built to serve a non-existent straight-linux tablet market. While the tablet influences are still around, the project has moved towards its original roots.

While Gnome 3 still isn't the perfect being that Gnome 2 (now MATE) was, the tweak tool being part of the default install and the extension library are helping make up for the shortcomings. One thing I really wanted to do is add custom startup applications to my session, this is accomplished via the tweak tool for now, since there is no UI for session management (yes, really).

I found this great article on how to do this, it involves creating a app.desktop file that can be seen by the tweak tool. This means that for every command line startup utility you want run on gnome session start, it needs a .desktop file. Ridiculous, but it works.

In case the site ever disappears, I've paraphrased the content below:

Create a app.desktop file in ~/.config/autostart, if this directory doesn't exist, create it.

Here's the basic content of a app.desktop file:

[Desktop Entry]
Type=Application
Exec=/usr/bin/xflux -z 12345
Hidden=false
X-GNOME-Autostart-enabled=true
Name[en_US]=xflux
Name=xflux
Comment[en_US]=Screen color temperature changer
Comment=Screen color temperature changer

Then head over to the Gnome Tweak Tool and go to the Startup Applications tab. From there, you can select the program for the app.desktop file you just made. Repeat as necessary.

Simple Ruby Speed Benchmarks

  2015-11-30 04:14:00 PST

To show the speed differences in some ruby applications, I wrote a simple ceaser cipher in a few different ways, then timed how long they took to run. I thought the results were interesting enough to post here.

Big thanks to Alan Skorkin for the simple timing code.

The first way creates a string of A-Z, then add the lower case letters to it, then split each character out, making an array. This implementation isn't a one-line array creation like the second.

The second way uses a string that's already created with A-Za-z, and splits them into an array.

The third way uses a hash of a-z, then creates the mappings for A-Za-z.

The fourth way uses a full hash of A-Za-z.

chart_with_upwards_trend Let's post some graphs! chart_with_upwards_trend

I removed the outliers from the four trials and made some graphs. First up, the average for 92 trials:

As you can see, it looks like the full hash implementation is the clear winner here.

Next up is the 92 trials plotted out:

Here's the code if you would like to run your own analysis.

#!/usr/bin/env ruby

# There are lots of ways to do things in ruby. Some are faster than others.
# This ruby script outputs benchmarks in CSV format
# Thanks to Alan Skorkin for the simple timing code
#   http://www.skorks.com/2010/03/timing-ruby-code-it-is-easy-with-benchmark/

require "benchmark"

print "HalfArray,FullArray,HalfHash,FullHash\n"

100.times do
  # Half array manipulation
  def ceaser_cipher(string)
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    alphabet += alphabet.downcase
    alphabet = alphabet.split(//)
    converted_string_array = []
    string.split(//).each do |l|
      if alphabet.include?(l)
        converted_string_array.push(alphabet[(alphabet.find_index(l) - 51).abs].swapcase)
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print ","

  # Full array manipulation
  def ceaser_cipher(string)
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(//)
    converted_string_array = []
    string.split(//).each do |l|
      if alphabet.include?(l)
        converted_string_array.push(alphabet[(alphabet.find_index(l) - 51).abs].swapcase)
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print ","

  # Half hash dictionary
  def ceaser_cipher(string)
    initial_dictionary = Hash[
      "a" => "z",
      "b" => "y",
      "c" => "x",
      "d" => "w",
      "e" => "v",
      "f" => "u",
      "g" => "t",
      "h" => "s",
      "i" => "r",
      "j" => "q",
      "k" => "p",
      "l" => "o",
      "m" => "n",
      "n" => "m",
      "o" => "l",
      "p" => "k",
      "q" => "j",
      "r" => "i",
      "s" => "h",
      "t" => "g",
      "u" => "f",
      "v" => "e",
      "w" => "d",
      "x" => "c",
      "y" => "b",
      "z" => "a"
    ]
    dictionary = {}
    initial_dictionary.each do |original, reversed|
      dictionary[original] = reversed
      dictionary[original.upcase] = reversed.upcase
    end
    converted_string_array = []
    string.split(//).each do |l|
      if dictionary.include?(l)
        converted_string_array.push(dictionary[l])
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print ","

  # Full hash dictionary
  def ceaser_cipher(string)
     dictionary = Hash[
      "A" => "Z",
      "B" => "Y",
      "C" => "X",
      "D" => "W",
      "E" => "V",
      "F" => "U",
      "G" => "T",
      "H" => "S",
      "I" => "R",
      "J" => "Q",
      "K" => "P",
      "L" => "O",
      "M" => "N",
      "N" => "M",
      "O" => "L",
      "P" => "K",
      "Q" => "J",
      "R" => "I",
      "S" => "H",
      "T" => "G",
      "U" => "F",
      "V" => "E",
      "W" => "D",
      "X" => "C",
      "Y" => "B",
      "Z" => "A",
      "a" => "z",
      "b" => "y",
      "c" => "x",
      "d" => "w",
      "e" => "v",
      "f" => "u",
      "g" => "t",
      "h" => "s",
      "i" => "r",
      "j" => "q",
      "k" => "p",
      "l" => "o",
      "m" => "n",
      "n" => "m",
      "o" => "l",
      "p" => "k",
      "q" => "j",
      "r" => "i",
      "s" => "h",
      "t" => "g",
      "u" => "f",
      "v" => "e",
      "w" => "d",
      "x" => "c",
      "y" => "b",
      "z" => "a"
    ]
    converted_string_array = []
    string.split(//).each do |l|
      if dictionary.include?(l)
        converted_string_array.push(dictionary[l])
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print "\n"
end

I'm not entirely familiar with low low level ruby, so I can't offer any grand insights, but I thought it was some decent code and a nice set of graphs.

Page: 5 of 32