| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #  Author:  Nicholas Hubbard | 
| 2 |  |  |  |  |  |  | #  WWW:     https://github.com/NicholasBHubbard/yabsm | 
| 3 |  |  |  |  |  |  | #  License: MIT | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | #  Miscellaneous tools to aid in the development of Yabsm. | 
| 6 |  |  |  |  |  |  | # | 
| 7 |  |  |  |  |  |  | #  See t/Tools.t for this modules tests. | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 9 |  |  | 9 |  | 627 | use strict; | 
|  | 9 |  |  |  |  | 20 |  | 
|  | 9 |  |  |  |  | 216 |  | 
| 10 | 9 |  |  | 9 |  | 35 | use warnings; | 
|  | 9 |  |  |  |  | 12 |  | 
|  | 9 |  |  |  |  | 165 |  | 
| 11 | 9 |  |  | 9 |  | 78 | use v5.16.3; | 
|  | 9 |  |  |  |  | 23 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | package App::Yabsm::Tools; | 
| 14 |  |  |  |  |  |  |  | 
| 15 | 9 |  |  | 9 |  | 4662 | use Time::Piece; | 
|  | 9 |  |  |  |  | 106292 |  | 
|  | 9 |  |  |  |  | 37 |  | 
| 16 | 9 |  |  | 9 |  | 4392 | use Feature::Compat::Try; | 
|  | 9 |  |  |  |  | 2420 |  | 
|  | 9 |  |  |  |  | 1455 |  | 
| 17 | 9 |  |  | 9 |  | 32825 | use Carp qw(confess); | 
|  | 9 |  |  |  |  | 21 |  | 
|  | 9 |  |  |  |  | 436 |  | 
| 18 | 9 |  |  | 9 |  | 47 | use File::Path qw(make_path); | 
|  | 9 |  |  |  |  | 12 |  | 
|  | 9 |  |  |  |  | 525 |  | 
| 19 | 9 |  |  | 9 |  | 52 | use File::Basename qw(dirname); | 
|  | 9 |  |  |  |  | 16 |  | 
|  | 9 |  |  |  |  | 765 |  | 
| 20 |  |  |  |  |  |  |  | 
| 21 | 9 |  |  | 9 |  | 53 | use Exporter qw(import); | 
|  | 9 |  |  |  |  | 13 |  | 
|  | 9 |  |  |  |  | 15629 |  | 
| 22 |  |  |  |  |  |  | our @EXPORT_OK = qw(have_prerequisites | 
| 23 |  |  |  |  |  |  | have_prerequisites_or_die | 
| 24 |  |  |  |  |  |  | arg_count_or_die | 
| 25 |  |  |  |  |  |  | with_error_catch_log | 
| 26 |  |  |  |  |  |  | have_sudo_access_to_btrfs | 
| 27 |  |  |  |  |  |  | have_sudo_access_to_btrfs_or_die | 
| 28 |  |  |  |  |  |  | is_btrfs_dir | 
| 29 |  |  |  |  |  |  | is_btrfs_dir_or_die | 
| 30 |  |  |  |  |  |  | is_btrfs_subvolume | 
| 31 |  |  |  |  |  |  | is_btrfs_subvolume_or_die | 
| 32 |  |  |  |  |  |  | nums_denote_valid_date | 
| 33 |  |  |  |  |  |  | nums_denote_valid_date_or_die | 
| 34 |  |  |  |  |  |  | system_or_die | 
| 35 |  |  |  |  |  |  | make_path_or_die | 
| 36 |  |  |  |  |  |  | i_am_root | 
| 37 |  |  |  |  |  |  | i_am_root_or_die | 
| 38 |  |  |  |  |  |  | ); | 
| 39 |  |  |  |  |  |  | our %EXPORT_TAGS = ( ALL => [ @EXPORT_OK ] ); | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | #################################### | 
| 42 |  |  |  |  |  |  | #            SUBROUTINES           # | 
| 43 |  |  |  |  |  |  | #################################### | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | sub have_prerequisites { | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | # Return 1 if we are running on a Linux OS and have sudo, OpenSSH, and | 
| 48 |  |  |  |  |  |  | # btrfs-progs installed. | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 4 | 50 |  | 4 | 0 | 1368 | return 0 unless $^O =~ /linux/i; | 
| 51 | 4 | 50 |  |  |  | 26934 | return 0 unless 0 == system('which btrfs >/dev/null 2>&1'); | 
| 52 | 0 | 0 |  |  |  | 0 | return 0 unless `ssh -V 2>&1` =~ /^OpenSSH/; | 
| 53 | 0 | 0 |  |  |  | 0 | return 0 unless 0 == system('which sudo >/dev/null 2>&1'); | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 0 |  |  |  |  | 0 | return 1; | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | sub have_prerequisites_or_die { | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | # Like &have_prerequisites except die if the prerequisites are not met. | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 0 | 0 |  | 0 | 0 | 0 | unless ($^O =~ /linux/i) { | 
| 63 | 0 |  |  |  |  | 0 | die "yabsm: internal error: not a Linux OS, this is a '$^O' OS\n"; | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 0 | 0 |  |  |  | 0 | unless (0 == system('which btrfs >/dev/null 2>&1')) { | 
| 67 | 0 |  |  |  |  | 0 | die 'yabsm: internal error: btrfs-progs not installed'."\n"; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 0 | 0 |  |  |  | 0 | unless (`ssh -V 2>&1` =~ /^OpenSSH/) { | 
| 71 | 0 |  |  |  |  | 0 | die 'yabsm: internal error: OpenSSH not installed'."\n"; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 0 | 0 |  |  |  | 0 | unless (0 == system('which sudo >/dev/null 2>&1')) { | 
| 75 | 0 |  |  |  |  | 0 | die 'yabsm: internal error: sudo not installed'."\n"; | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 0 |  |  |  |  | 0 | return 1; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | sub arg_count_or_die { | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | # Carp::Confess unless $num_args is in range $lower-$upper. If $lower equals | 
| 84 |  |  |  |  |  |  | # '_' then it is assumed to be 0 and if $upper equals '_' it is assumed to | 
| 85 |  |  |  |  |  |  | # be infinity. | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 3356 |  |  | 3356 | 0 | 10341 | my $lower    = shift; | 
| 88 | 3356 |  |  |  |  | 3461 | my $upper    = shift; | 
| 89 | 3356 |  |  |  |  | 3476 | my $num_args = scalar @_; | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 3356 | 100 |  |  |  | 5259 | $lower = 0 if $lower eq '_'; | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 3356 |  |  |  |  | 3690 | my $lower_ok = $lower <= $num_args; | 
| 94 | 3356 | 100 |  |  |  | 4736 | my $upper_ok = $upper eq '_' ? 1 : $upper >= $num_args; | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 3356 | 100 | 100 |  |  | 8099 | unless ($lower_ok && $upper_ok) { | 
| 97 | 4 |  |  |  |  | 20 | my $caller    = ( caller(1) )[3]; | 
| 98 | 4 |  |  |  |  | 13 | my $error_msg = "yabsm: internal error: called '$caller' with $num_args args but it expects"; | 
| 99 | 4 |  |  |  |  | 6 | my $range_msg; | 
| 100 | 4 | 100 |  |  |  | 14 | if    ($upper eq '_')    { $range_msg = "at least $lower args" } | 
|  | 1 | 100 |  |  |  | 3 |  | 
| 101 | 1 |  |  |  |  | 4 | elsif ($lower == $upper) { $range_msg = "$lower args"          } | 
| 102 | 2 |  |  |  |  | 5 | else                     { $range_msg = "$lower-$upper args"   } | 
| 103 | 4 |  |  |  |  | 50 | confess("$error_msg $range_msg"); | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  |  | 
| 106 | 3352 |  |  |  |  | 4477 | return 1; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | sub with_error_catch_log { | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | # Call $sub with @args within a Feature::Compat::Try try/catch block to catch | 
| 112 |  |  |  |  |  |  | # any exception and log it to /var/log/yabsm instead of killing the program. | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 0 |  |  | 0 | 0 | 0 | my $sub  = shift; | 
| 115 | 0 |  |  |  |  | 0 | my @args = @_; | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | try { | 
| 118 |  |  |  |  |  |  | $sub->(@args); | 
| 119 |  |  |  |  |  |  | } | 
| 120 | 0 |  |  |  |  | 0 | catch ($e) { | 
| 121 |  |  |  |  |  |  | if (-f '/var/log/yabsm' && open(my $fh, '>>', '/var/log/yabsm')) { | 
| 122 |  |  |  |  |  |  | $e =~ s/^\s+|\s+$//g; | 
| 123 |  |  |  |  |  |  | my $t = localtime(); | 
| 124 |  |  |  |  |  |  | my ($yr, $mon, $day, $hr, $min) = map { sprintf '%02d', $_ } $t->year, $t->mon, $t->mday, $t->hour, $t->min; | 
| 125 |  |  |  |  |  |  | say $fh "[${yr}_${mon}_${day}_$hr:$min]: $e"; | 
| 126 |  |  |  |  |  |  | close $fh; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | sub have_sudo_access_to_btrfs { | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | # Return 1 if we can run 'btrfs' with 'sudo -n' and return 0 otherwise. | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 0 |  |  | 0 | 0 | 0 | arg_count_or_die(0, 0, @_); | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 0 |  |  |  |  | 0 | return 0+(0 == system('sudo -n btrfs --help >/dev/null 2>&1')); | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub have_sudo_access_to_btrfs_or_die { | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | # Wrapper around have_sudo_access_to_btrfs() that Carp::Confess's if it | 
| 143 |  |  |  |  |  |  | # returns false. | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 0 |  |  | 0 | 0 | 0 | arg_count_or_die(0, 0, @_); | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 0 |  |  |  |  | 0 | my $username = getpwuid $<; | 
| 148 |  |  |  |  |  |  |  | 
| 149 | 0 | 0 |  |  |  | 0 | have_sudo_access_to_btrfs() ? return 1 : die("yabsm: internal error: no sudo access rights to 'btrfs' while running as user '$username'"); | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | sub is_btrfs_dir { | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | # Return 1 if $dir is a directory residing on a btrfs subvolume | 
| 155 |  |  |  |  |  |  | # and return 0 otherwise. | 
| 156 |  |  |  |  |  |  |  | 
| 157 | 0 |  |  | 0 | 0 | 0 | arg_count_or_die(1, 1, @_); | 
| 158 |  |  |  |  |  |  |  | 
| 159 | 0 |  |  |  |  | 0 | my $dir = shift; | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 0 | 0 |  |  |  | 0 | return 0 unless -d $dir; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 |  |  |  |  | 0 | return 0+(0 == system("btrfs property list '$dir' >/dev/null 2>&1")); | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | sub is_btrfs_dir_or_die { | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | # Wrapper around is_btrfs_dir() that Carp::Confess's if it returns false. | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 0 |  |  | 0 | 0 | 0 | arg_count_or_die(1, 1, @_); | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 0 |  |  |  |  | 0 | my $dir = shift; | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 0 | 0 |  |  |  | 0 | is_btrfs_dir($dir) ? return 1 : die("yabsm: internal error: '$dir' is not a directory residing on a btrfs filesystem\n") | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | sub is_btrfs_subvolume { | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | # Return 1 if $dir is a btrfs subvolume on this OS and return 0 | 
| 180 |  |  |  |  |  |  | # otherwise. | 
| 181 |  |  |  |  |  |  | # | 
| 182 |  |  |  |  |  |  | # A btrfs subvolume is identified by inode number 256 | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 0 |  |  | 0 | 0 | 0 | arg_count_or_die(1, 1, @_); | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 0 |  |  |  |  | 0 | my $dir = shift; | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 0 | 0 |  |  |  | 0 | return 0 unless is_btrfs_dir($dir); | 
| 189 |  |  |  |  |  |  |  | 
| 190 | 0 |  |  |  |  | 0 | my $inode_num = (split /\s+/, `ls -di '$dir' 2>/dev/null`, 2)[0]; | 
| 191 |  |  |  |  |  |  |  | 
| 192 | 0 |  |  |  |  | 0 | return 0+(256 == $inode_num); | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | sub is_btrfs_subvolume_or_die { | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | # Wrapper around is_btrfs_subvolume() that Carp::Confess's if it returns | 
| 198 |  |  |  |  |  |  | # false. | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 0 |  |  | 0 | 0 | 0 | arg_count_or_die(1, 1, @_); | 
| 201 |  |  |  |  |  |  |  | 
| 202 | 0 |  |  |  |  | 0 | my $dir = shift; | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 0 | 0 |  |  |  | 0 | is_btrfs_subvolume($dir) ? return 1 : die("yabsm: internal error: '$dir' is not a btrfs subvolume") | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub nums_denote_valid_date { | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | # Return 1 if passed a year, month, month-day, hour, and minute | 
| 210 |  |  |  |  |  |  | # that denote a valid date and return 0 otherwise. | 
| 211 |  |  |  |  |  |  |  | 
| 212 | 214 |  |  | 214 | 0 | 801 | arg_count_or_die(5, 5, @_); | 
| 213 |  |  |  |  |  |  |  | 
| 214 | 214 |  |  |  |  | 354 | my ($yr, $mon, $day, $hr, $min) = @_; | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 214 | 100 |  |  |  | 411 | return 0 unless $yr  >= 1; | 
| 217 | 212 | 100 | 66 |  |  | 511 | return 0 unless $mon >= 1 && $mon <= 12; | 
| 218 | 210 | 100 | 66 |  |  | 515 | return 0 unless $hr  >= 0 && $hr  <= 23; | 
| 219 | 208 | 100 | 66 |  |  | 492 | return 0 unless $min >= 0 && $min <= 59; | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | # month days are a bit more complicated to figure out | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 207 | 100 | 33 |  |  | 862 | if ($mon == 1 || $mon == 3 || $mon == 5 || $mon == 7 || $mon == 8 || $mon == 10 || $mon == 12) { | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 224 | 200 | 100 | 66 |  |  | 524 | return 0 unless $day >= 1 && $day <= 31; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  | elsif ($mon == 4 || $mon == 6 || $mon == 9 || $mon == 11) { | 
| 227 | 3 | 100 | 66 |  |  | 19 | return 0 unless $day >= 1 && $day <= 30; | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  | else { # February | 
| 230 | 4 |  |  |  |  | 6 | my $is_leap_yr; | 
| 231 |  |  |  |  |  |  |  | 
| 232 | 4 | 50 |  |  |  | 19 | if    ($yr % 400 == 0) { $is_leap_yr = 1 } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  |  | 100 |  |  |  |  |  | 
| 233 | 0 |  |  |  |  | 0 | elsif ($yr % 100 == 0) { $is_leap_yr = 0 } | 
| 234 | 2 |  |  |  |  | 4 | elsif ($yr % 4   == 0) { $is_leap_yr = 1 } | 
| 235 | 2 |  |  |  |  | 4 | else                   { $is_leap_yr = 0 } | 
| 236 |  |  |  |  |  |  |  | 
| 237 | 4 | 100 |  |  |  | 9 | my $upper = $is_leap_yr ? 29 : 28; | 
| 238 |  |  |  |  |  |  |  | 
| 239 | 4 | 100 | 66 |  |  | 27 | return 0 unless $day >= 1 && $day <= $upper; | 
| 240 |  |  |  |  |  |  | } | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 202 |  |  |  |  | 387 | return 1; | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | sub nums_denote_valid_date_or_die { | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | # Wrapper around &nums_denote_valid_date that Carp::Confess's if it | 
| 248 |  |  |  |  |  |  | # returns false. | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 39 |  |  | 39 | 0 | 689 | arg_count_or_die(5, 5, @_); | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 39 | 100 |  |  |  | 70 | unless ( nums_denote_valid_date(@_) ) { | 
| 253 | 2 |  |  |  |  | 7 | my ($yr, $mon, $day, $hr, $min) = @_; | 
| 254 | 2 |  |  |  |  | 38 | confess("yabsm: internal error: '${yr}_${mon}_${day}_$hr:$min' does not denote a valid yr_mon_day_hr:min date"); | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  |  | 
| 257 | 37 |  |  |  |  | 81 | return 1; | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | sub system_or_die { | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | # Wrapper around system that Carp::Confess's if the system command exits | 
| 263 |  |  |  |  |  |  | # with a non-zero status. Redirects STDOUT and STDERR to /dev/null. | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 2 |  |  | 2 | 0 | 2628 | open my $NULLFD, '>', '/dev/null'; | 
| 266 | 2 |  |  |  |  | 50 | open my $OLD_STDOUT, '>&', STDOUT; | 
| 267 | 2 |  |  |  |  | 36 | open my $OLD_STDERR, '>&', STDERR; | 
| 268 | 2 |  |  |  |  | 62 | open STDOUT, '>&', $NULLFD; | 
| 269 | 2 |  |  |  |  | 43 | open STDERR, '>&', $NULLFD; | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 2 |  |  |  |  | 7051 | my $status = system @_; | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 2 |  |  |  |  | 131 | open STDOUT, '>&', $OLD_STDOUT; | 
| 274 | 2 |  |  |  |  | 43 | open STDERR, '>&', $OLD_STDERR; | 
| 275 | 2 |  |  |  |  | 20 | close $NULLFD; | 
| 276 | 2 |  |  |  |  | 20 | close $OLD_STDOUT; | 
| 277 | 2 |  |  |  |  | 18 | close $OLD_STDERR; | 
| 278 |  |  |  |  |  |  |  | 
| 279 | 2 | 100 |  |  |  | 29 | unless (0 == $status) { | 
| 280 | 1 |  |  |  |  | 105 | confess("yabsm: internal error: system command '@_' exited with non-zero status '$status'"); | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 | 1 |  |  |  |  | 69 | return 1; | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | sub make_path_or_die { | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | # Wrapper around File::Path::make_path() that Carp::Confess's if the path | 
| 289 |  |  |  |  |  |  | # cannot be created. The UID and GID of the $path will be set to that of the | 
| 290 |  |  |  |  |  |  | # deepest existing sub-directory in $path. | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 0 |  |  | 0 | 0 |  | my $path = shift; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 0 | 0 |  |  |  |  | $path =~ /^\// | 
| 295 |  |  |  |  |  |  | or die "yabsm: internal error: '$path' is not an absolute path starting with '/'"; | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 0 |  |  |  |  |  | my $dir = $path; | 
| 298 |  |  |  |  |  |  |  | 
| 299 | 0 |  |  |  |  |  | until (-d $dir) { | 
| 300 | 0 |  |  |  |  |  | $dir = dirname($dir); | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 0 |  |  |  |  |  | my ($uid, $gid) = (stat $dir)[4,5]; | 
| 304 |  |  |  |  |  |  |  | 
| 305 | 0 | 0 |  |  |  |  | -d $path and return 1; | 
| 306 |  |  |  |  |  |  |  | 
| 307 | 0 | 0 |  |  |  |  | make_path($path, {uid => $uid, group => $gid}) and return 1; | 
| 308 |  |  |  |  |  |  |  | 
| 309 | 0 |  |  |  |  |  | my $username = getpwuid $<; | 
| 310 |  |  |  |  |  |  |  | 
| 311 | 0 |  |  |  |  |  | die "yabsm: error: could not create path '$path' while running as user '$username'\n"; | 
| 312 |  |  |  |  |  |  | } | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | sub i_am_root { | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | # Return 1 if current user is root and return 0 otherwise. | 
| 317 |  |  |  |  |  |  |  | 
| 318 | 0 |  |  | 0 | 0 |  | return 0+(0 == $<); | 
| 319 |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | sub i_am_root_or_die { | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | # Die unless running as the root user. | 
| 324 |  |  |  |  |  |  |  | 
| 325 | 0 |  |  | 0 | 0 |  | arg_count_or_die(0, 0, @_); | 
| 326 |  |  |  |  |  |  |  | 
| 327 | 0 | 0 |  |  |  |  | unless (i_am_root()) { | 
| 328 | 0 |  |  |  |  |  | my $username = getpwuid $<; | 
| 329 | 0 |  |  |  |  |  | confess("yabsm: internal error: not running as root - running as '$username'"); | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 0 |  |  |  |  |  | return 1; | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | 1; |