2012-10-25

Granting Root access to all XOrg / X11 Displays on a machine.

Jump here if you just want the code

xauth is hard

There are many techniques for allowing root ( or any other user ) to open programs on your display.

When not configured to do so, simple things don't work, and there are 2 general results you get:

No previous attempt at getting xauth based auth to work

> sudo gvim 
No protocol specified
E233: cannot open display
E852: The child process failed to start the GUI
No protocol specified
                                                                                             
Press ENTER or type command to continue

With Previous attempts at using xauth based auth

Invalid MIT-MAGIC-COOKIE-1 key
E233: cannot open display
E852: The child process failed to start the GUI
Invalid MIT-MAGIC-COOKIE-1 key


This case occurs I believe due to your X display having a unique authentication key per session.

But your display likely stores an Xauthority database somewhere on disk

I discovered this little gem when looking at some of the code VirtualGL/Bumblebee uses ( because it has to run a secret display as a different user, and that different user has to be able to write to your screen )
set_xauth() {

# common case (works in almost all tested environments (except of lightdm)):
XAUTHORITY="$(ps wwax -C X,Xorg -o args= --sort=-stime | grep -m 1 -o '\B[-]auth\s*/var\S*auth\S*' | cut -d ' ' -f 2)"

# kdm and some others:
# XAUTHORITY="$(find /var/run/xauth/A${DISPLAY}-*|tail -n1)"

# gdm:
# XAUTHORITY="/var/gdm/${DISPLAY}.Xauth"

# slim:
# XAUTHORITY="/var/run/slim.auth"

# lightdm:
# XAUTHORITY="/var/run/lightdm/root/${DISPLAY}"

}


And as I'm running kdm I took a look at the relevant command.

$ find /var/run/xauth/A${DISPLAY}-*|tail -n1
/var/run/xauth/A:0-xNjOfc


Aha. Useful.

sudo xauth -f /var/run/xauth/A\:0-xNjOfc  list
#ffff##:  MIT-MAGIC-COOKIE-1  711f067eae4ec73599dc38dbfaa164f0

Oh handy. That hex code is the key you need to access the relevant display :D.

$ xterm
Invalid MIT-MAGIC-COOKIE-1 key
xterm: Xt error: Can't open display: %s
$ xauth add :0 MIT-MAGIC-COOKIE-1 700f067eae4ec73599dc38dbe7a164f1
$ xterm 
$ # success!


Putting it all together

Here's a blob of shell script I have in /root/.bash_profile:
setup_xauth() {
 authfile=$( echo /var/run/xauth/A${DISPLAY}-* );
 if [ -z "${DISPLAY}" ]; then
  return
 fi
 if [ ! -f $authfile ]; then
  return;
 fi
 if [ ! -s $authfile ]; then
  return;
 fi
 authtoken=$( xauth -f "$authfile"  nlist | cut -d" " -f 9 );
 xauth add $DISPLAY MIT-MAGIC-COOKIE-1 $authtoken
}

setup_xauth;


Note, its essential that you check for read access to the file, especially if you plan on using this in a non-root users profile code.

If xauth can't read the authfile, it will just block and do nothing, and this is very bad to have in your profile.

Additionally, due to this being defined as a function, all roots shells will have a convenience function 'setup_xauth' that you can call at any time in the event you've had to change $DISPLAY, or in the event you want to access a local X display from a VT

export DISPLAY=:0
setup_xauth
gvim # gvim launches on :0 

2012-10-11

How to create files with a leading period in the filename with Microsoft Explorer

I have to post this, because this seems a very frequently asked question on the internet, and while there is a straight-forward solution, most people propose bizarre solutions that circumvent the problem by using some other tool.

If you dig deeper, you'll find working solutions in comments, but they're incomplete and its not obvious at first that it even works.

The Problem


The problem is simple: You wish to create a unix-style hidden file, such as ".htaccess" , ".gitignore", or ".netrc", or a unix-style hidden folder, for whatever reason.

While this is not a problem for literally any tool other than Windows Explorer, attempting to do this in Explorer yields the following error:

You must type a file name.
The Windows Explorer "Rename" Dialog showing the error "You must type a file name."

The Solution

Most proponents suggest strange solutions such as using cmd.exe or notepad to do your dirty work,  and even Microsoft Developers seem to think that letting Explorer do this is crazy and suggest using some other tool

However, all that is unnecessary.

All that is required is writing an additional dot ( period ) at the tailing end.

If you wanted '.htaccess', instead, write '.htaccess.'
If you wanted '.gitignore' , instead, write '.gitignore.'

Explorer will silently strip the last dot and give you the file name you wanted, with no fuss.

The Windows Explorer Rename Dialog showing the error "You must type a file name." as a result of the user specifying ".gitignore" as the file name

Windows Explorer prompting the user to confirm they want to change a file name extension, as a result of specifying the filename as ".gitignore."

Windows Explorer showing the successfully renamed file as ".gitignore" after confirming the file extension change, showing how the trailing period has been removed


2011-02-22

Testing your File::ShareDir based dist now possible.

For the last few months, every time I've had a dist that needed File::ShareDir to do its dirty work, I've used various tricks to make it work.
  • Simply not test it:
    Sad as this may seem, this is pretty much the primary approach because it was too confusing
  • Invest a bit of code into overriding sharedir behaviour
    This usually involved having some coderef or lazy-loaded attribute that was normally populated by File::ShareDir, instead provided during test via hard-coding it.

Enter Test::File::ShareDir

I uploaded Test::File::ShareDir this morning to CPAN, which lets you do this:
use Test::More;

use FindBin;

use Test::File::ShareDir
  -root => "$FindBin::Bin/../",
  -share => {
    -module => { 'My::Module' => 'share/MyModule' }
  };
This configuration would be sufficient to use in a test in t/ for a distribution shipping My::Module along with its corresponding shared directory share/MyModule. If you were shipping this dist with Dist::Zilla, you'd have something like this in dist.ini
[ModuleShareDirs]
My::Module = share/MyModule
I plan to add support for 'package' style ShareDir support, but for now, module share dirs are sufficient. Enjoy =).

2011-01-08

Making a Minting Profile as a CPANized Dist.

... or one more reason why Dist::Zilla is awesome.

Minting With Dzil

Minting is a term we use for "Creating a new distribution from a template of sorts". Since Dist::Zilla 2.101230 ( 2010-05-03 23:42:27 America/New_York ), there has been a command for Dist::Zilla to facilitate setting up a new distribution.

$ dzil new Acme-An-Example
# [DZ] making target dir /tmp/Acme-An-Example
# [DZ] writing files to /tmp/Acme-An-Example
# [DZ] dist minted in ./Acme-An-Example
$ find Acme-An-Example/
# Acme-An-Example/
# Acme-An-Example/dist.ini
# Acme-An-Example/lib
# Acme-An-Example/lib/Acme
# Acme-An-Example/lib/Acme/An
# Acme-An-Example/lib/Acme/An/Example.pm
$ cat Acme-An-Example/dist.ini
# name    = Acme-An-Example
# author  = Kent Fredric 
# license = Perl_5
# copyright_holder = Kent Fredric 
# copyright_year   = 2011
# 
# version = 0.001
# 
# [@Basic]
$ cat Acme-An-Example/lib/Acme/An/Example.pm
# use strict;
# use warnings;
# package Acme::An::Example;
# 
# 1;

And while this is a good starting point, once you've gotten into Dist::Zilla, you'll probably find it somewhat lacking and find yourself doing things over and over again.

For this, we have "Minting Profiles".

Basic Minting Profiles

.

Minting Profiles have been in Dist::Zilla since 4.101780 ( 2010-06-27 14:30:55 America/New_York ).

The first thing you'll tend to do, is make a minting profile in ~/.dzil

dzil.org's minting-profile tutorial adequately covers the innards of how this works, but summarised, its lots like dist.ini. You have a profile.ini in a directory in ~/.dzil/profiles/$profilename/ and it will control how your dist is created, and you can then throw together new dists as simply as:

$ dzil new -p $profilename Acme-An-Example

In the absence of -p $profilename, if there is a ~/.dzil/profiles/default/, that will be used instead.

This is pretty convenient.

Me, I had a very simple default profile for a while that did most of what I needed to do:

; ~/.dzil/profiles/default/profile.ini
[Author::KENTNL::DistINI]

That behaves more-or-less identical to how normal dzil new operates, but it generates a custom dist.ini from my custom Author::KENTNL::DistINI plugin. This is based on DistINI just tuned for how I like it. Its more or less a template ;).

; Generated by Dist::Zilla::Plugin::Author::KENTNL::DistINI version 0.01023312 at Fri Jan  7 20:05:56 2011
name             = Acme-An-Example
author           = Kent Fredric 
license          = Perl_5
copyright_holder = Kent Fredric 

; Uncomment this to bootstrap via self 
; [Bootstrap::lib]

[@KENTNL]
version_major     = 0
version_minor     = 1
; the following data denotes when this minor was minted
version_rel_year  = 2011
version_rel_month = 1
version_rel_day   = 7
version_rel_hour  = 20
version_rel_time_zone = Pacific/Auckland
twitter_hash_tags = #perl #cpan

[Prereqs]

CPAN Centralization

However, many people like to use CPAN as their file storage mechanism, and centralise all their perly bits they might need in different locations so they can just get their current favourite configuration with a handy :

cpanm --interactive --verbose Dist::Zilla::MintingProfile::Author::KENTNL 

A Word on Name-spaces

Before we go further, I think it important to plead my rationale behind the "Author::" prefix I'm using now, as I feel its an important concern.

As we have seen with Dist::Zilla there have been a slew of PluginBundles with CPANID's in their name, to the point that there is a copious amount of name-space pollution in the PluginBundle name-space, and more Author bundles than task-bundles, which was really what the name-space was designed for, and I'll freely admit, I am guilty of this crime as well, but I'm petitioning you to help reduce this annoyance in future modules.

From a CPAN testers perspective, the annoyance of lots of CPANID-dists is similar to the annoyance of the whole DPCHRIST:: subspace, and that if this pattern continues, it will mean for the testers who do not wish to test everyones personal modules, that they will have to work hard to avoid this. If DPCHRIST:: had used something like Author::DPCHRIST:: instead, I doubt so many people would be horrified by it, because you can just have a policy/rule that excludes ^Author::, and everyone else who goes that way can be quietly ignored.

Then we could probably rationally add that same restriction to the irc announce bots, the "recent modules" list and soforth, and possibly even apply special indexing restrictions or something so people wouldn't even have to know those modules exist on cpan!

So, for the sake of cleanliness, semantics, and general global sanity, I ask you to join me with my Author:: naming policy to voluntarily segregate modules that are most likely of only personal use from those that have more general application.

Dist::Zilla::Plugin::Foo                 # [Foo]                 dist-zilla plugins for general use
Dist::Zilla::Plugin::Author::KENTNL::Foo # [Author::KENTNL::Foo] foo that only KENTNL will probably have use for
Dist::Zilla::PluginBundle::Classic       # [@Classic]            A bundle that can have practical use by many
Dist::Zilla::PluginBundle::Author::KENTNL #[@Author::KENTNL]     KENTNL's primary plugin bundle
Dist::Zilla::MintingProfile::Default     # A minting profile that is used by all
Dist::Zilla::MintingProfile::Author::KENTNL # A minting profile that only KENTNL will find of use.

Making Dist::Zilla::MintingProfile::Author::YOURID

First, we'll start with the above default empty profile with a basic dist.ini

$ dzil new Dist-Zilla-MintingProfile-Author-YOURID
And then the guts of that Minting Profile is pretty basic.
use strict;
use warnings;

package Dist::Zilla::MintingProfile::Author::YOURID;

# ABSTRACT: YOURID's Minting Profile

use Moose;
use namespace::autoclean;
with 'Dist::Zilla::Role::MintingProfile::ShareDir';


__PACKAGE__->meta->make_immutable;
no Moose;
1;

This is a deceptively simple piece of magic that took me a little while to fully grok.

Next, we make a 'profile' directory in our dist.

$ mkdir -p Dist-Zilla-MintingProfile-Author-YOURID/share/profiles/
And in that, we can put one or many profiles. For simplicity, we'll just start off with a 'default' profile.
$ mkdir -p Dist-Zilla-MintingProfile-Author-YOURID/share/profiles/default/
$ pushd Dist-Zilla-MintingProfile-Author-YOURID/share/profiles/default/

Now, you could just stick the same profile.ini you had above in ~/.dzil there, and you're mostly done with the hard part. However, I'll go a little more into detail so you get an idea of what use it is.

Make a 'skel' dir

Make a 'skel' dir holding a selection of templated-files you want in all new dists

Here is the most notable ones in mine

$ mkdir skel
# stuff directory with files
$ find skel/
# skel/
# skel/.gitignore
# skel/.perltidyrc
# skel/Changes
# skel/perlcritic.rc
# skel/weaver.ini
$ cat skel/Changes
# Release history for {{ $dist->name }}
# 
# {{ '{{$NEXT}}' }}
#
#        First version, released on an unsuspecting world.
#
$ cat skel/.gitignore
# .build
# {{ $dist->name }}-*

{{ $dist->name }} is expanded during 'new' to the name of the intended dist, and {{ '{{$NEXT}}' }} is just a nasty hack so that the literal string {{$NEXT}} turns up in the changelog file so the Changelog plugin keeps working.

For more in-depth understanding, please read The dzil minting profile tutorial

Adding support for the skel directory

You now need to tell your profile.ini about that skel directory if you want it to mean anything.

[GatherDir::Template]
root = skel
include_dotfiles = 1 ; I want the dot files! 
./profile.ini    # this file ---> indicates inclusion of
./skel                           #      /
./skel/.gitignore          <-----------/
./skel/.perltidyrc         <----------/
./skel/Changes             <---------/
./skel/perlcritic.rc       <--------/
./skel/weaver.ini          <-------/

Other misc profile additions

Now most people will probably just put in
./skel/dist.ini

With some template variables expanded, but I myself prefer the dedicated module approach for dist.ini, so I add that to profile.ini

[GatherDir::Template]
root = skel
include_dotfiles = 1 ; I want the dot files! 

[Author::KENTNL::DistINI]
And for good measure, I want every new dist to automatically have git set up with it, so I add that plugin too.
[GatherDir::Template]
root = skel
include_dotfiles = 1 ; I want the dot files! 

[Author::KENTNL::DistINI]
[Git::Init]

Gluing it together

Now if you've been following me, you'll have a directory that looks a lot like this:
dist.ini
lib/
lib/Dist
lib/Dist/Zilla
lib/Dist/Zilla/MintingProfile
lib/Dist/Zilla/MintingProfile/Author
lib/Dist/Zilla/MintingProfile/Author/YOURID.pm
share/
share/profiles
share/profiles/default
share/profiles/default/profile.ini
share/profiles/default/skel
share/profiles/default/skel/.gitignore
share/profiles/default/skel/.perltidyrc
share/profiles/default/skel/Changes
share/profiles/default/skel/perlcritic.rc
share/profiles/default/skel/weaver.ini

And you're probably wondering how the 'share' directory and its contents will be seen by 'YOURID.pm' after installation.

The magic is this stanza in your dist.ini

[ModuleShareDirs]
Dist::Zilla::MintingProfile::Author::YOURID = share/profiles 

Yeah, at first that baffled me too.

Into the guts of File::ShareDir

Dist::Zilla utilizes sharedir in 2 places, 1. In the module that does the minting, and 2. Using some instructions injected in your install tool.

During Install

Lets pretend there is a directory, we'll call it $x, which is known as the "base directory" for all Things File::ShareDir::Install installs, which is also known to to File::ShareDir.

For example:

/usr/lib64/perl5/vendor_perl/5.12.2/auto/share/    # $x 
/usr/lib64/perl5/vendor_perl/5.12.2/               # module install dir.

The ModuleShareDirs plugin tells File::ShareDir::Install that the directory 'share/profiles' should be installed in a path associated with the module, i.e.:

$x/module/Dist-Zilla-MintingProfile-Author-YOURID/ <= share/profiles/ 

So, during install, the files in share/profiles/* will be copied to that directory.

.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/skel/perlcritic.rc
.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/skel/weaver.ini
.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/skel/.perltidyrc
.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/skel/.gitignore
.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/skel/Changes
.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/profile.ini
.../Dist/Zilla/MintingProfile/Author/YOURID.pm

And that is not all that scary =)

How your profile uses that

Having seen how it installs to the file-system, how the plug-in works should be a bit of a no brainer.

  • dzil new -P Author::YOURID -p default Some-Module-Name
  • Dist::Zilla, sees -P, and loads the respective profile from @INC, Dist::Zilla::MintingProfile::Author::YOURID
  • Your minting profile uses that sharedir role, and asks File::ShareDir for the directory associated with 'Dist-Zilla-MintingProfile-Author-YOURID', which of course returns that '.../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/' we installed above.
  • The Role then determines which sub-profile to use ( default, as specified by -p ) and then returns that path ( now .../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/ )
  • .../auto/share/module/Dist-Zilla-MintingProfile-Author-YOURID/default/profile.ini is then read and a new distribution is constructed using the instructions therein
  • And presto, you have a newly minted dist =):
    $ cd Some-Module-Name;
    $ find
    # ./.git 
    # ... a bunch of .git files ...
    # ./dist.ini
    # ./weaver.ini
    # ./perlcritic.rc
    # ./Changes
    # ./.perltidyrc
    # ./.gitignore
    # ./lib
    # ./lib/Some
    # ./lib/Some/Module
    # ./lib/Some/Module/Name.pm
    

Hopefully thats enough to get you started, but...

There is one warning you must uptake with the use of file sharedir.

ONCE YOU INSTALL A FILE IN A SHAREDIR FROM A CPAN DIST, IT IS THERE FOR GOOD

At least, it will be there till somebody manually deletes it, at least in the current implementation of CPAN.

This means if you decide to put a file in skel/, and then later decide you don't want that file in skel/, you're going to have a problem when something decides to "add all of skel/ to your new dist".

For vendor-wrapped/packaged stuff ( ie: Redhat, Debian, Gentoo ) you're fine, those systems have package management that guarantee atomicity somewhat, but the CPAN toolchain ( at least, in my experience ) provides very little guarantee in this regard. This may change in the future, but that's how it seems to be now. But now I've warned you, you'll hopefully not bump into that =).

2010-12-29

Discover Where your Firefox Profile Directory is.

I've often had the challenge of knowing "Which profile am I running? Where is it loaded from ? " with firebox. Especially on Windows, where there is a dizzying maze of inconsistency, which only seems to be getting worse. Thankfully, Firefox 4.0 ( and possibly earlier ) has a solution of sorts.
about:support

This helpful dialogue summarises a whole bunch of useful things that are probably cause for your woes.

However, they've done one thing, well meaning, but completely stupid in my estimation.

Now to me, this is a big problem, because mostly, I've had a common issue with anything "open a directory" related simply not work, and for me, it would be much much more practical if it just told me where it is ( this also really gets on my goat with the download manager, because open pretty almost never works as expected , especially as directories, and I just wish it would tell me where the damned file is instead of making me do a dance ).

So, I got busy and poked around in the guts of about:support with firebug, and found the source code for that button in chrome://. As a result, here is a nice little scriptlet that will tell you where that location is without needing to open some external application!

javascript:alert(Services.dirsvc.get("ProfD", Ci.nsIFile).path);

When you are on the about:support page, copy and paste that string as-is into your address bar and press enter, if you are lucky, you'll get an alert box telling you where to look

Hosted by imgur.com

Hopefully, this technique will help out where others fail ( Such as the one odd incident I saw on IRC today where the user has rm -r ~/.mozilla but they still somehow have Firefox remembering what their profile looks like.