152 lines
4.2 KiB
Perl
152 lines
4.2 KiB
Perl
|
#!/usr/bin/env perl
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use YAML;
|
||
|
use File::Basename qw(fileparse);
|
||
|
use List::MoreUtils qw(uniq);
|
||
|
use Getopt::Std;;
|
||
|
use Data::Dumper;
|
||
|
use File::HomeDir;
|
||
|
use File::Path qw(make_path);
|
||
|
use 5.010;
|
||
|
|
||
|
# return a perl structure by reader a YAML file
|
||
|
sub read_yml_file_to_struct {
|
||
|
my $file = shift;
|
||
|
open my $fh, '<', $file or die;
|
||
|
$/ = undef;
|
||
|
my $data = <$fh>;
|
||
|
close $fh;
|
||
|
return Load($data);
|
||
|
}
|
||
|
|
||
|
|
||
|
# some files or directories may be included in a listed directory
|
||
|
# remove those from the list and print a warning
|
||
|
sub remove_transclusion {
|
||
|
my $data = shift;
|
||
|
my @files = uniq @{$data->{"files"}};
|
||
|
my @directories = uniq @{$data->{"directories"}};
|
||
|
|
||
|
for(my $i=0; $i <= $#directories; $i++) {
|
||
|
my $dir = $directories[$i];
|
||
|
next if ($dir eq "");
|
||
|
|
||
|
# check if a file is contained by a directory
|
||
|
foreach my $file (@files) {
|
||
|
my($filename, $dirs, $suffix) = fileparse($file);
|
||
|
if($dirs =~ m/^$dir/) {
|
||
|
say STDERR "WARNING: $dir contains $file";
|
||
|
$file = "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# check if a directory is contained by another directory
|
||
|
# if so, mark them for deletion later
|
||
|
# we can't remove directly from the array because we
|
||
|
# are iterating in it in the main loop
|
||
|
for(my $j=0; $j <= $#directories; $j++) {
|
||
|
if($j != $i) {
|
||
|
my $dir2 = $directories[$j];
|
||
|
next if ($dir2 eq "");
|
||
|
if($dir =~ m/$dir2/) {
|
||
|
say STDERR "WARNING: $dir2 contains $dir";
|
||
|
$directories[$i] = "";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# remove empty entries
|
||
|
@directories = sort grep { /^./ } @directories;
|
||
|
@files = sort grep { /^./ } @files;
|
||
|
$data->{"files"} = \@files;
|
||
|
$data->{"directories"} = \@directories;
|
||
|
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
my %opts;
|
||
|
my ($impermanence_home, $persist_home, $configuration_file, $data, $ret);
|
||
|
getopts("t:d:u:", \%opts);
|
||
|
|
||
|
# check if using test mode to validate a configuration file
|
||
|
if(defined $opts{t}) {
|
||
|
say STDERR "WARNING: test mode enabled";
|
||
|
$configuration_file = $opts{t};
|
||
|
} else {
|
||
|
|
||
|
# -d and -u flags are mandatory
|
||
|
if(! defined $opts{d} || ! defined $opts{u}) {
|
||
|
say STDERR "usage: $0 [-t] -d directory -u user";
|
||
|
exit 1;
|
||
|
}
|
||
|
|
||
|
# test if root
|
||
|
if($< != 0) {
|
||
|
say STDERR "$0 must be run as root.";
|
||
|
exit 1;
|
||
|
}
|
||
|
|
||
|
$impermanence_home = File::HomeDir->users_home($opts{u});
|
||
|
$persist_home = $opts{d};
|
||
|
$configuration_file = $persist_home."/".$opts{u}."/impermanence.yml";
|
||
|
}
|
||
|
|
||
|
if ( ! -f $configuration_file ) {
|
||
|
say STDERR "The file ".$configuration_file." can't be found";
|
||
|
exit 1;
|
||
|
}
|
||
|
|
||
|
$data = read_yml_file_to_struct($configuration_file);
|
||
|
$data = remove_transclusion $data;
|
||
|
|
||
|
if(defined $opts{t}) {
|
||
|
exit 0;
|
||
|
}
|
||
|
|
||
|
# is this already mounted?
|
||
|
$ret = `df $impermanence_home | awk -v dest=$impermanence_home '/^mfs/ && \$NF == dest { print }'`;
|
||
|
if ($ret =~ m/^mfs/) {
|
||
|
say STDERR "ERROR: $impermanence_home is already mounted with MFS";
|
||
|
exit 2;
|
||
|
}
|
||
|
my $fs = `swapctl | tail -n 1 | cut -d ' ' -f 1 | tr -d '\n'`;
|
||
|
|
||
|
$ret = system("mount_mfs", "-s", $data->{size}, $fs, $impermanence_home);
|
||
|
if($ret != 0) {
|
||
|
say STDERR "ERROR: mounting the mfs filesystem errored with error $ret";
|
||
|
exit 2;
|
||
|
}
|
||
|
|
||
|
foreach (@{$data->{files}}) {
|
||
|
my $old_file = $persist_home."/".$opts{u}."/".$_;
|
||
|
my $new_file = $impermanence_home."/".$_;
|
||
|
|
||
|
my ($filename, $dirs, $suffix) = fileparse($new_file);
|
||
|
|
||
|
# recursively create missing directories to hold files
|
||
|
# give ownership to the user and apply chmod 700
|
||
|
if ( ! -e $dirs ) {
|
||
|
make_path($dirs, { chmod => 0700, owner => $opts{u} });
|
||
|
}
|
||
|
symlink($old_file, $new_file);
|
||
|
}
|
||
|
|
||
|
foreach (@{$data->{directories}}) {
|
||
|
my $old_dir = $persist_home."/".$opts{u}."/".$_;
|
||
|
my $new_dir = $impermanence_home."/".$_;
|
||
|
|
||
|
my ($dir, $dirs, $suffix) = fileparse($new_dir);
|
||
|
say "$old_dir / $new_dir / $dir / $dirs ";
|
||
|
|
||
|
# recursively create missing directories to hold dir symlinks
|
||
|
# give ownership to the user and apply chmod 700
|
||
|
if ( ! -e $dirs ) {
|
||
|
make_path($dirs, { chmod => 0700, owner => $opts{u} });
|
||
|
}
|
||
|
symlink($old_dir, $new_dir);
|
||
|
}
|
||
|
|