#!/usr/local/bin/perl -w # # $Id: chmod,v 1.2 2004/08/05 14:17:43 cwest Exp $ # # $Log: chmod,v $ # Revision 1.2 2004/08/05 14:17:43 cwest # cleanup, new version number on website # # Revision 1.1 2004/07/23 20:10:01 cwest # initial import # # Revision 1.3 1999/03/09 02:44:57 abigail # Fixed SybolicMode -> SymbolicMode typo. # # Revision 1.2 1999/03/08 03:07:28 abigail # Major documentation tweaks. # # Revision 1.1 1999/03/07 12:03:54 abigail # Initial revision # # use strict; my ($VERSION) = '$Revision: 1.2 $' =~ /([.\d]+)/; my $warnings = 0; # Print a usuage message on a unknown option. # Requires my patch to Getopt::Std of 25 Feb 1999. $SIG {__WARN__} = sub { if (substr ($_ [0], 0, 14) eq "Unknown option") {die "Usage"}; require File::Basename; $0 = File::Basename::basename ($0); $warnings = 1; warn "$0: @_"; }; $SIG {__DIE__} = sub { require File::Basename; $0 = File::Basename::basename ($0); if (substr ($_ [0], 0, 5) eq "Usage") { die < 1; my $mode = shift; my $symbolic = 0; if ($mode =~ /[^0-7]/) { require SymbolicMode; $symbolic = 1; } elsif ($mode !~ /^[0-7]{1,4}$/) { die "invalid mode: $mode\n" } my %ARGV; %ARGV = map {$_ => 1} @ARGV if $options {H}; sub modify_file; if (exists $options {R}) { # Recursion. require File::Find; File::Find::find (\&modify_file, @ARGV); } else { foreach my $file (@ARGV) { modify_file $file; } } # File::Find is weird. If called with a directory, it will call # the sub with "." as file name, while having chdir()ed to the # directory. But it doesn't do that in recursion, just the top # level ones. And it ain't true that $File::Find::name eq # "$File::Find::dir/$_" in all cases. # But it shouldn't matter in this case. sub modify_file { my $file = @_ ? shift : $_; # Now, if this is a symbolic link, it points somewhere, # *and* we are following symbolic links, we recurse. # This may never end as symlinks can form loops. if (-l $file && -e $file && ($options {L} || $options {H} && $ARGV {$file})) { # We don't want to recurse symlinks that just happen to # have the same name as one of the arguments, hence the local. # Remember that $file is relative to the current directory. local $ARGV {readlink $file} = 0; File::Find::find (\&modify_file, readlink $file); return; } unless (-e $file) { warn "$file does not exist\n"; return; } my $realmode = $mode; if ($symbolic) { $realmode = SymbolicMode::mod ($mode, $file) or die "invalid mode: $mode\n"; } chmod oct ($realmode), $file or warn "$!\n"; } exit $warnings; __END__ =pod =head1 NAME B -- change permissions of files. =head1 SYNOPSIS B [B<-R> [B<-H> | B<-L> | B<-P>]] I I [I ...] =head1 DESCRIPTION B sets the permissions of files. The first argument after the options is permission the files should be given. =head2 OPTIONS B accepts the options described below. The options B<-L>, B<-H> and B<-P> are mutally exclusive, and only the last given option will be honoured. All of B<-L>, B<-H> and B<-P> require the B<-R> option to be set first. =over 4 =item B<-R> Recurse into directories. Any directories are recursively traversed, and all files and directories will change owner. =item B<-L> Follow symbolic links. By default, B will not follow symbolic links. This is a potential dangerous option, as B will not check for cycles. Be careful. This option requires the B<-R> option to be set. =item B<-H> Follow symbolic links of command line files/directories only. This option requires the B<-R> option to be set. =item B<-P> Do not follow symbolic links at all. This option requires the B<-R> option to be set. =back =head2 MODES Is are either absolute, or symbolic. An absolute I is an octal number, calculated by OR-ing the following values: =for html
4000

Suid on execution.

2000

Guid on execution.

1000

The sticky(8) bit is turned on.

0400

Read permission for the ownwer of the file.

0200

Write permission for the ownwer of the file.

0100

Execute permission for the ownwer of the file.

0040

Read permission for those in the group as the group of the file.

0020

Write permission for those in the group as the group of the file.

0010

Execute permission for those in the group as the group of the file.

0004

Read permission for all others.

0002

Write permission for all others.

0001

Execute permission for all others.

=for html
Symbolic I is a comma separated list of Is. Each I has the following format: =for html
      [who] operator [permissions] [operator [permissions] ...]
I consists of zero or more of the following symbols: =over =item B Permissions for the user (owner) of the file. =item B Permissions for the group of the file. =item B Permissions for all others. =item B Permissions for everyone. =back If I is omitted, it will default to B, but the value of your I is taken into account. B will then not set a permission that is masked by your I. The I is one of: =over =item B<+> Add permissions. If no Is are given, this action is ignored. If I is absent, set the permission bit as indicated by Is, but respect the I settings. If I is given, set the permission bits as indicated by Is, for those groups indicated by I. =for html
-
Revoke permissions. If no Is are given, this action is ignored. If I is absent, revoke the I bit as indicated by permissions, but respect the umask settings. If I is given, revoke the permission bits as indicated by Is, for those groups indicated by I. =for html
-
Set permissions. The permission bits indicated by I are all cleared. If I isn't given, all permission bits are cleared. Then, if I isn't given, those permission bits in I whose corresponding bit in the I is clear are set. Otherwise, the permission bits are set as indicated by I and I. =back I consists of zero or more of: =over =item B The read permission bit. =item B The write permission bit. =item B The execute permission bit. =item B The execute permission bit, but only if the target is either a directory, or has at least one execution bit set in the unmodified permission bits. Furthermore, this permission is ignored if I is either B> or B>. =item B The suid and guid bit. These will have no effect in combination with the B I setting. =item B The sticky bit. This makes sense only for the others group, however, it will be ignored if B is the only group in the I part of the I. =item B The original permissions of the user. =item B The original permissions of the group. =item B The original permissions for others. =back =head1 ENVIRONMENT The working of B is not influenced by any environment variables. =head1 BUGS It is unlikely there are no bugs. The documentation is at best ambiguous. The OpenBSD documentation does not match the OpenBSD implementation. Furthermore, the implementations of Solaris, SunOS, HP, and GNU all differ from each other, and from OpenBSD. This manual page needs work. The module I needs to be documented. B parses a symbolic mode once for each file. That is too much redundant work. B can loop forever when symbolic links create cycles. B uses I to recurse. This manual should have been written in Texinfo, LaTeX, or a funky SGML application. B, B, B and B are all broken beyond belief. =head1 STANDARDS It does not make sense to talk about standards in a chmod manual page. =head1 REVISION HISTORY $Log: chmod,v $ Revision 1.2 2004/08/05 14:17:43 cwest cleanup, new version number on website Revision 1.1 2004/07/23 20:10:01 cwest initial import Revision 1.3 1999/03/09 02:44:57 abigail Fixed SybolicMode -> SymbolicMode typo. Revision 1.2 1999/03/08 03:07:28 abigail Major documentation tweaks. Revision 1.1 1999/03/07 12:03:54 abigail Initial revision =head1 AUTHOR The Perl implementation of B was written by Abigail, I. =head1 COPYRIGHT and LICENSE This program is copyright by Abigail 1999. This program is free and open software. You may use, copy, modify, distribute, and sell this program (and any modified variants) in any way you wish, provided you do not restrict others from doing the same. =cut