[OpenAFS] uss command deprecated

Russ Allbery rra@stanford.edu
Thu, 26 Jan 2012 17:26:32 -0800


Dan Scott <danieljamesscott@gmail.com> writes:

> We use uss with a template file during account creation, to create a
> volume and mountpoint, and to configure a skeleton directory and to set
> permissions.

> Is the uss command going to be removed? If so, is there an alternative
> method of using similar templates? I couldn't find anything in the
> manual.

There are no immediate plans to remove it.  However, I'd like to
understand your use case better, since I've not seen a use of uss that
couldn't be replaced by a fairly simple shell script.  For example, here
is the script we use to create user home directories.

This is not exactly trivial, and it does rely on some internal tools like
volcreate, but it's also not complex and could be made substantially
simpler if one didn't mind editing it whenever policy changed.  Most of it
is error checking.

#!/usr/bin/perl -w
$ID = q$Id: create-user,v 1.15 2010-06-14 15:15:37 hallk Exp $;
#
# create-user -- Create a user AFS volume and populate it.
#
# Written by Russ Allbery <rra@stanford.edu>
# Copyright 2003, 2004, 2006 Board of Trustees, Leland Stanford Jr. University
#
# Creates a user volume and populates it with the appropriate skel files and
# the like.  Sets up initial AFS permissions in various portions of the
# account.  Uses volcreate to do the actual volume creation.  Note that unlike
# the other create-* scripts, this script is not interactive.  It takes the
# user name as a command-line argument.

##############################################################################
# Site configuration
##############################################################################

# The path to the file that contains the default quota amounts.
$DEFAULTQUOTA   = '/afs/ir/service/afs/data/default-quota';

# The full path to fs.  Allow for Linux where the preferred location may be on
# local disk, and normally avoid the pubsw wrapper.
($FS)  = grep { -x $_ } qw(/usr/bin/fs /usr/afsws/bin/fs /usr/pubsw/bin/fs);
$FS ||= '/usr/afsws/bin/fs';

# The full path to pts.  Allow for Linux where the preferred location may be
# on local disk.
($PTS)  = grep { -x $_ } qw(/usr/bin/pts /usr/pubsw/bin/pts);
$PTS ||= '/usr/pubsw/bin/pts';

# The path to the skeleton files that are installed in a new account.
#($SKEL)  = grep { -x $_ } qw(/etc/lsdb/skel /usr/pubsw/etc/skel);
#$SKEL ||= '/usr/pubsw/etc/skel';
$SKEL           = '/usr/pubsw/etc/skel';

# The path to the volcreate script.
$VOLCREATE      = '/afs/ir/service/afs/scripts/volcreate';

# The path to the volume release script.
$VOLRELEASE     = '/afs/ir/service/afs/scripts/volrelease';

##############################################################################
# Modules and declarations
##############################################################################

require 5.004;

use strict;
use subs qw(chmod chown mkdir system);
use vars qw($DEFAULTQUOTA $FS $ID $PTS $SKEL $VOLCREATE $VOLRELEASE);

use File::Copy qw(copy);

##############################################################################
# Overrides for error checking
##############################################################################

sub chmod {
    my $status = CORE::chmod ($_[0], $_[1]);
    unless ($status) {
        warn "$0: chmod $_[1] failed: $!\n";
    }
    return $status;
}

sub chown {
    my $status = CORE::chown ($_[0], $_[1], $_[2]);
    unless ($status) {
        warn "$0: chown $_[2] failed: $!\n";
    }
    return $status;
}

sub mkdir {
    my $status = CORE::mkdir ($_[0], $_[1]);
    unless ($status) {
        warn "$0: mkdir $_[0] failed: $!\n";
    }
    return $status;
}

sub system {
    my $status = CORE::system (@_);
    if ($status != 0) {
        die "$0: @_ exited with status ", ($status >> 8), "\n";
    }
    return $status;
}

##############################################################################
# Implementation
##############################################################################

# Get the default quota for user volumes.
sub default_quota {
    open (QUOTA, $DEFAULTQUOTA) or die "$0: can't open $DEFAULTQUOTA: $!\n";
    local $_;
    my $quota;
    while (<QUOTA>) {
        next if /^\s*$/;
        next if /^\s*\#/;
        if (/^\s*user:\s*(\d+)\s*$/) {
            $quota = $1;
        }
    }
    close QUOTA;
    die "$0: no user quota default found in $DEFAULTQUOTA\n" unless $quota;
    return $quota;
}

# Look for a user in PTS.  If the user is found, returns their UID; otherwise,
# abort.
sub pts_examine {
    my ($user) = @_;
    die "$0: bad characters in SUNet ID $user\n" if ($user =~ /[\s\'\\]/);
    my $output = `$PTS examine '$user' 2>&1`;
    my $status = $?;
    $output =~ s/^libprot: no such entry Could not get afs tokens.*\n//;

    # For some reason, a regex anchored with ^ still doesn't match the output,
    # even though we've removed the libprot line.  I don't understand at all,
    # but not anchoring the regex does work.  Perl bug?
    if ($status == 0 && $output =~ /Name: \Q$user\E, id: (\d+),/) {
        return $1;
    } else {
        warn $output;
        if ($status != 0) {
            die "$0: PTS examine for $user failed with status ",
                ($status >> 8), "\n";
        }
        exit 1;
    }
}

# Create the user's volume.  Assumes that we're already authenticated as a
# user who can create volumes.
sub create_volume {
    my ($user) = @_;
    my $quota = default_quota;
    unless (length ($user) > 1) {
        die "$0: user $user must be at least two characters\n";
    }
    unless ($user =~ /^[a-z0-9]+$/) {
        die "$0: invalid characters in user $user\n";
    }
    my ($f, $s) = ($user =~ /^(\w)(\w)/);
    my $path = "/afs/.ir/users/$f/$s/$user";
    system ($VOLCREATE, '-t', 'user', "user.$user", $quota, $path,
            $user, 'all');
    system ($VOLRELEASE, "users.$f.$s");
}

# Set up the user directory.
sub setup_directory {
    my ($user) = @_;
    umask 022;

    unless (length ($user) > 1) {
        die "$0: user $user must be at least two characters\n";
    }
    unless ($user =~ /^[a-z0-9]+$/) {
        die "$0: invalid characters in user $user\n";
    }
    my ($f, $s) = ($user =~ /^(\w)(\w)/);
    my $path = "/afs/.ir/users/$f/$s/$user";
    my $uid = pts_examine ($user);
    my $gid = 37;
    unless (-d $path) {
        die "$0: home directory $path invalid: $!\n";
    }

    system ($FS, 'mkmount', "$path/.backup", "user.$user.backup");
    mkdir ("$path/private", 0700);
    mkdir ("$path/public",  0755);
    mkdir ("$path/Mail",    0700);
    mkdir ("$path/News",    0700);
    mkdir ("$path/WWW",     0755);
    chown ($uid, $gid, $path);
    chown ($uid, $gid, "$path/private");
    chown ($uid, $gid, "$path/public");
    chown ($uid, $gid, "$path/Mail");
    chown ($uid, $gid, "$path/News");
    chown ($uid, $gid, "$path/WWW");
    system ($FS, 'setacl', $path,          'system:campushosts', 'l');
    system ($FS, 'setacl', $path,          'system:www-servers', 'l');
    system ($FS, 'setacl', "$path/public", 'system:campushosts', 'rl');
    system ($FS, 'setacl', "$path/WWW",    'system:www-servers', 'rl');
    opendir (SKEL, $SKEL) or die "$0: can't open $SKEL: $!\n";
    for my $file (grep { !/^\.\.?$/ } readdir SKEL) {
        copy ("$SKEL/$file", "$path/$file")
            or die "$0: can't copy $SKEL/$file to $path/$file: $!\n";
        chown ($uid, $gid, "$path/$file");
    }
    closedir SKEL;

    open (KLOGIN, "> $path/public/.klogin")
        or die "$0: can't create $path/public/.klogin: $!\n";
    print KLOGIN "$user\@IR.STANFORD.EDU\n";
    close KLOGIN or die "$0: can't flush $path/public/.klogin: $!\n";
    open (K5LOGIN, "> $path/public/.k5login")
        or die "$0: can't create $path/public/.k5login: $!\n";
    print K5LOGIN "$user\@stanford.edu\n";
    close K5LOGIN or die "$0: can't flush $path/public/.k5login: $!\n";
    chown ($uid, $gid, "$path/public/.klogin");
    chown ($uid, $gid, "$path/public/.k5login");
    symlink ("public/.klogin", "$path/.klogin")
        or die "$0: can't symlink $path/.klogin: $!\n";
    symlink ("public/.k5login", "$path/.k5login")
        or die "$0: can't symlink $path/.k5login: $!\n";
}

##############################################################################
# Main routine
##############################################################################

# Clean up for error messages.
$0 =~ s%.*/%%;

my $user = shift or die "$0: no user specified\n";
create_volume ($user);
setup_directory ($user);

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>