apt-get install debian-wizard

Insider infos, master your Debian/Ubuntu distribution

  • About
    • About this blog
    • About me
    • My free software history
  • Support my work
  • Get the newsletter
  • More stuff
    • Support Debian Contributors
    • Other sites
      • My company
      • French Blog about Free Software
      • Personal Website (French)
  • Mastering Debian
  • Contributing 101
  • Packaging Tutorials
You are here: Home / Archives for Random / Tips and tricks

How to choose your SSH agent with Wayland and systemd

November 10, 2025 by Raphaël Hertzog 4 Comments

If you read the above title, you might wonder how the switch to wayland (yes, the graphical stack replacing the venerable X11) can possibly relate to SSH agents. The answer is easy.

For as long as I can remember, as a long time user of gpg-agent as SSH agent (because my SSH key is a GPG sub-key) I relied on /etc/X11/Xsession.d/90gpg-agent that would configure the SSH_AUTH_SOCK environment variable (pointing to gpg-agent’s socket) provided that I added enable-ssh-support in ~/.gnupg/gpg-agent.conf.

Now when I switched to Wayland, that shell script used in the startup sequence of Xorg was no longer used. During a while I cheated a bit by setting SSH_AUTH_SOCK directly in my ~/.bashrc. But that only works for terminals, and not for other applications that are started by the session manager (which is basically systemd --user).

So how is that supposed to work out of the box nowadays? The SSH agents (as packaged in Debian) have all adopted the same trick, their .socket unit have an ExecStartPost setting which runs systemctl --user set-environment SSH_AUTH_SOCK=some-value. This command dynamically modifies the environment of the running systemd daemon and thus influences the environment for the future units started. Putting this in a socket unit ensures an early run, before most of the applications are started so it’s a good choice. They tend to also explicitly ensure this with a directive like Before=graphical-session-pre.target.

However, in a typical installation you end up with multiple SSH agents (right now I have ssh-agent, gpg-agent, and gcr-ssh-agent), which one is the one that the user ends up using? Well, that is not clearly defined, the one that wins is the one that runs last… because each of them overwrites the value in the systemd environment.

Some of them fight to have that place (cf #1079246 for gcr-ssh-agent) by setting explicit After directives. In the above bug I argue that we should let gpg-agent.socket have the priority since that’s the only one that is not enabled by default and that requires the user to opt-in. However, ultimately there will always be cases where you will want to be explicit about the SSH agent that should win.

You could rely on systemd overrides to add/remove ordering directives but that’s pretty fragile. Instead the right way to deal with this is to “mask” the socket units of the SSH agents that you don’t want. Note that disabling (i.e. systemctl --user disable) either will not work[1] or will not be sufficient[2]. In my case, I wanted to keep gpg-agent.socket so I masked gcr-ssh-agent.socket and ssh-agent.socket:

$ systemctl --user mask ssh-agent.socket gcr-ssh-agent.socket
Created symlink '/home/rhertzog/.config/systemd/user/ssh-agent.socket' → '/dev/null'.
Created symlink '/home/rhertzog/.config/systemd/user/gcr-ssh-agent.socket' → '/dev/null'.

Note that if you want that behaviour to apply to all users of your computer, you can use sudo systemctl --global mask ssh-agent.socket gcr-ssh-agent.socket. Now on next login, you will only get a single ssh agent socket unit that runs and the SSH_AUTH_SOCK value will thus be predictable again!

Hopefully you will find that useful as it’s already the second time that I stumble upon this either for me or for a relative. Next time, I will know where to look it up. 🙂

[1]: If you try to run systemctl --user disable gcr-ssh-agent.socket, you will get a message saying that it will not work because the unit is enabled for all users at the “global” level. You can do it with --global instead of --user but it doesn’t help, cf below.

[2]: Disabling an unit basically means stopping to explicitely schedule its startup as part of a desired target. However, the unit can still be started as a dependency of other units and that’s the case here because a socket unit will typically be pulled in by its corresponding service unit.

How to create custom RSS feeds with WordPress

January 7, 2011 by Raphaël Hertzog

WordPress has many alternate built-in feeds: per category, per tag, per author, per search-keyword. But in some cases, you want feeds built with some more advanced logic. Let’s look at the available options.

WordPress advanced built-in feeds

You can create feeds for “unions” or “intersections” of tags, you just have to use a URL like /tag/foo,bar/feed/ (all articles tagged with foo or bar) or /tag/foo+bar/feed/ (all articles tagged with foo and bar).

You can also have feeds excluding a category, although that requires you to know the category identifier (and hardcode it in the URL like this: /?feed=rss2&cat=-123 where 123 is the category id that you want to exclude).

But there’s no simple way to have a feed that excludes articles with a given tag. The best solution found involves creating a custom feed. I’ll show you a variation of this below.

Creating a custom feed

  1. First of, install the Feed Wrangler plugin, it will take care of registering our custom feeds with wordpress.
  2. Go to “Settings > Feed Wrangler” in your WordPress administrative interface and create a new feed, let’s call it “myfeed”.
  3. You should now create a “feed-myfeed.php” file and put it in your current theme’s directory. The initial content of that file should be this:
    <?php
    include('wp-includes/feed-rss2.php');
    ?>

    <?php include('wp-includes/feed-rss2.php'); ?>

  4. At this point, you already have a new feed that you can access at /feed/myfeed/ (or /?feed=myfeed). It’s a complete feed like the main one.

Now, we’re going to look at ways to customize this feed. We’re going to do this by changing/overriding the default query that feed-rss2.php’s loop will use.

A feed excluding articles with a tag

If you want to create a feed that excludes the tag “foo”, you could use this:

<?php
global $wp_query;
$tag = get_term_by("slug", "foo", "post_tag");
$args = array_merge(
        $wp_query->query,
        array('tag__not_in' => array($tag->term_id))
);
query_posts($args);
include('wp-includes/feed-rss2.php');
?>

<?php global $wp_query; $tag = get_term_by("slug", "foo", "post_tag"); $args = array_merge( $wp_query->query, array('tag__not_in' => array($tag->term_id)) ); query_posts($args); include('wp-includes/feed-rss2.php'); ?>

That was relatively easy, thanks to the “tag__not_in” query parameter. Now you can further customize the feed by adding supplementary query parameters to the $args array. The documentation of query_posts details the various parameters that you can use.

A feed excluding articles with a custom field (meta-data)

I went further because I did not want to use a tag to exclude some posts: that tag would have been public even if it was only meaningful to me. So I decided to use a custom field to mark the posts to exclude from my new feed. I named the field “no_syndication” and I always give it the value “1”.

This time it’s not so easy because we have no query parameter that can be used to exclude posts based on custom fields. We’re going to use the “post__not_in” parameter that can be used to exclude a list of posts. But we must first generate the list of posts that we want to exclude. Here we go:

<?php
global $wp_query;
$excluded = array();
$args_excluded = array(
    'numberposts'     => -1,
    'meta_key'        => 'no_syndication',
    'meta_value'      => 1,
    'post_type'       => 'post',
    'post_status'     => 'published'
);
foreach (get_posts($args_excluded) as $item) {
        $excluded[] = $item->ID;
}
$args = array_merge(
        $wp_query->query,
        array('post__not_in' => $excluded)
);
query_posts($args);
include('wp-includes/feed-rss2.php');
?>

<?php global $wp_query; $excluded = array(); $args_excluded = array( 'numberposts' => -1, 'meta_key' => 'no_syndication', 'meta_value' => 1, 'post_type' => 'post', 'post_status' => 'published' ); foreach (get_posts($args_excluded) as $item) { $excluded[] = $item->ID; } $args = array_merge( $wp_query->query, array('post__not_in' => $excluded) ); query_posts($args); include('wp-includes/feed-rss2.php'); ?>

A feed with modified content

You might want to add a footer to the articles that are syndicated. I use the Ozh’ Better Feed plugin for this but it applies to all your feeds.

You could do that sort of transformation only in your customized feed by using the WordPress filter named the_content_feed.

Here’s a simple example:

<?php
function myfeed_add_footer($content) {
        return $content . "<hr/>My footer here";
}
add_filter('the_content_feed', 'myfeed_add_footer');
include('wp-includes/feed-rss2.php');
?>

<?php function myfeed_add_footer($content) { return $content . "<hr/>My footer here"; } add_filter('the_content_feed', 'myfeed_add_footer'); include('wp-includes/feed-rss2.php'); ?>

I’ll stop here but obviously you have lots of options and many ways to tweak all the snippets above. They have been tested with WordPress 3.0.4.

Note that in all those examples, I took care to not duplicate the code from feed-rss2.php, instead I used include() to execute it. That way my custom feeds will automatically benefit from all the future enhancements and fixes made by the WordPress developers.

But if you have to modify the XML structure of your custom feeds, you can paste the content of feed-rss2.php in your file and change it like you want…

Git, CIA and branch merging

July 7, 2008 by Raphaël Hertzog

Dear Joey, we also had this problem for dpkg, that’s why I hacked the /usr/local/bin/git-commit-notice script that we’re using on Alioth to do something like this instead:

while read oldrev newrev refname; do
    branchname=${refname#refs/heads/}
    [ "$branchname" = "master" ] && branchname=""
    for merged in $(git rev-parse --not --branches | grep -v $(git rev-parse $refname) | git rev-list --reverse --stdin $oldrev..$newrev); do
         /usr/local/bin/git-ciabot.pl $merged $branchname
    done
done

while read oldrev newrev refname; do branchname=${refname#refs/heads/} [ "$branchname" = "master" ] && branchname="" for merged in $(git rev-parse --not --branches | grep -v $(git rev-parse $refname) | git rev-list --reverse --stdin $oldrev..$newrev); do /usr/local/bin/git-ciabot.pl $merged $branchname done done

It will stop git rev-list each time that it encounters a commit that is available in any of the other branches present in the repository and thus when you merge a branch, you only see the merge commit in CIA.

You should also note that the script is smarter as it calls CIA only for branch updates, not for tag creation (and other kinds of updates) where it only leads to strange errors IIRC.

Assembling bits of history with git: take two

July 28, 2007 by Raphaël Hertzog

Following my previous article, I had some interesting comments introducing me to git-filter-branch (which is a new function coming from cogito’s cg-admin-rewritehist). This command is really designed to rewrite the history and you can do much more changes… it enabled me to fix the dates/authors/committers/logs of all the commits that were created with git_load_dirs. It can also be used to add one or more “parent commits” to any commit.

In parallel I discovered some problems with the git repository that I created: the tags were no more pointing to my master branch. This is because git rebase won’t convert them while rewriting history.

This lead me to redo everything from scratch. This time I used git-filter-branch instead. The man page even gives an example of how to link two branches together as if one was the predecessor of the other. Here’s how you can do it: let’s bind together “old” and “new”… the resulting branch will be “new-rewritten”.

$ git rev-parse old
0975870bb1631379f2da798fa78736a4fe32960a
$ git checkout new
$ git-filter-branch --tag-name-filter=cat --parent-filter \
"sed -e 's/^$/-p 0975870bb1631379f2da798fa78736a4fe32960a/'" \
new-rewritten
[...]
Rewritten history saved to the new-rewritten branch

Short explanation: the only commit without a parent commit (thus matching the empty regex “^$”) is the root commit and this one is changed to have a parent (-p) which is the last commit of the branch “old”.

At the end, you remove all the temporary branches, keep only what’s needed and repack everything to save space:


$ git branch -D old new
$ git prune
$ git repack -a -d

  • 1
  • 2
  • Next Page »

Get the Debian Handbook

Available as paperback and as ebook.
Book cover

Email newsletter

Get updates and exclusive content by email, join the Debian Supporters Guild:

Follow me

  • Email
  • Facebook
  • GitHub
  • RSS
  • Twitter

Discover my French books

Planets

  • Planet Debian

Archives

I write software, books and documentation. I'm a Debian developer since 1998 and run my own company. I want to share my passion and knowledge of the Debian ecosystem. Read More…

Tags

3.0 (quilt) Activity summary APT aptitude Blog Book Cleanup conffile Contributing CUT d-i Debconf Debian Debian France Debian Handbook Debian Live Distro Tracker dpkg dpkg-source Flattr Flattr FOSS Freexian Funding Git GNOME GSOC HOWTO Interview LTS Me Multiarch nautilus-dropbox News Packaging pkg-security Programming PTS publican python-django Reference release rolling synaptic Ubuntu WordPress

Recent Posts

  • How to choose your SSH agent with Wayland and systemd
  • Freexian is looking to expand its team with more Debian contributors
  • Freexian’s report about Debian Long Term Support, July 2022
  • Freexian’s report about Debian Long Term Support, June 2022
  • Freexian’s report about Debian Long Term Support, May 2022

Copyright © 2005-2021 Raphaël Hertzog