#!/usr/bin/perl

=begin metadata

Name: mkfifo
Description: make named pipes
Author: Jeffrey S. Haemer
Author: Louis Krupp
License: perl

=end metadata

=cut


use strict;

use File::Basename qw(basename);
use POSIX "mkfifo";
use Getopt::Std;

use constant EX_SUCCESS => 0;
use constant EX_FAILURE => 1;

use vars qw($opt_m);

my $Program = basename($0);

getopts('m:') and @ARGV or usage();

sub default_mode {
	return 0666 & ~(umask);
}

sub usage {
	warn "$Program: [-m mode] filename...\n";
	exit EX_FAILURE;
}

sub sym_perms {
	my $sym = shift;
	my $mode = default_mode();

	my %who = (u => 0700, g => 0070, o => 0007);
	my %what = (r => 0444, w => 0222, x => 0111);

	my ($who, $how, $what) = split /([+-=])/, $sym;
	$who =~ s/a/ugo/g;

	my @who = split //, $who;
	my $who_mask = 0;
	foreach (@who) {
		$who_mask |= $who{$_};
	}

	my @what = split //, $what;
	my $what_mask = 0;
	foreach (@what) {
		$what_mask |= $what{$_};
	}

	if ($how eq '+') {
		$mode |= ($who_mask & $what_mask);
	} elsif ($how eq '-') {
		$mode &= ~($who_mask & $what_mask);
	} elsif ($how eq '=') {
		$mode = ($mode & ~$who_mask) | ($who_mask & $what_mask);
	}
}

sub get_mode {
	my $mode = shift;
	my $real_mode;

	if ($mode =~ /^0?[0-7]{1,3}$/) {
		$real_mode = oct $mode;
	} else {
		$real_mode = sym_perms($mode);
	}
	if ($real_mode < 0) {
		warn "$Program: bad file mode: '$mode'\n";
		exit EX_FAILURE;
	}
	return $real_mode;
}

my $mode = defined $opt_m ? get_mode($opt_m) : default_mode();

my $rc = EX_SUCCESS;
foreach my $fifo (@ARGV) {
	if (-e $fifo) {
		warn "$Program: '$fifo': file already exists\n";
		$rc = EX_FAILURE;
		next;
	}
	unless (mkfifo($fifo, $mode)) {
		warn "$Program: '$fifo': $!\n";
		$rc = EX_FAILURE;
		next;
	}
}
exit $rc;

=head1 NAME

mkfifo - make named pipes

=head1 SYNOPSIS

mkfifo "-m mode" filename ...

=head1 DESCRIPTION

=over 2

Create one or more named pipes, in the order specified,
with the mode given.

If no mode is given, create them with mode 0666, modified by the umask.

=back

=head1 OPTIONS AND ARGUMENTS

=over 8

=item I<-m>

The mode the fifo should be created with.

Numbers must be three octal digits (as for B<chmod(1)>.

Symbolic modes, specified the way you can for B<chmod(1)>
(such as C<g+w>) are also acceptable.

=item I<filename ...>

One or more fifo names to create

=back

=head1 AUTHOR

Jeffrey S. Haemer and Louis Krupp

=head1 SEE ALSO

  chmod(1) umask(1) mkfifo(2)

=cut
