1*7c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl -w 2*7c478bd9Sstevel@tonic-gate# 3*7c478bd9Sstevel@tonic-gate# CDDL HEADER START 4*7c478bd9Sstevel@tonic-gate# 5*7c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the 6*7c478bd9Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only 7*7c478bd9Sstevel@tonic-gate# (the "License"). You may not use this file except in compliance 8*7c478bd9Sstevel@tonic-gate# with the License. 9*7c478bd9Sstevel@tonic-gate# 10*7c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11*7c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 12*7c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions 13*7c478bd9Sstevel@tonic-gate# and limitations under the License. 14*7c478bd9Sstevel@tonic-gate# 15*7c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 16*7c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17*7c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 18*7c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 19*7c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 20*7c478bd9Sstevel@tonic-gate# 21*7c478bd9Sstevel@tonic-gate# CDDL HEADER END 22*7c478bd9Sstevel@tonic-gate# 23*7c478bd9Sstevel@tonic-gate# 24*7c478bd9Sstevel@tonic-gate# Copyright 2004 Sun Microsystems, Inc. All rights reserved. 25*7c478bd9Sstevel@tonic-gate# Use is subject to license terms. 26*7c478bd9Sstevel@tonic-gate# 27*7c478bd9Sstevel@tonic-gate#ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate# 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gaterequire 5.005; 31*7c478bd9Sstevel@tonic-gateuse strict; 32*7c478bd9Sstevel@tonic-gateuse locale; 33*7c478bd9Sstevel@tonic-gateuse Errno; 34*7c478bd9Sstevel@tonic-gateuse Fcntl; 35*7c478bd9Sstevel@tonic-gateuse File::Basename; 36*7c478bd9Sstevel@tonic-gateuse Getopt::Std; 37*7c478bd9Sstevel@tonic-gateuse Getopt::Long qw(:config no_ignore_case bundling); 38*7c478bd9Sstevel@tonic-gateuse POSIX qw(locale_h getuid getgid); 39*7c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(textdomain gettext); 40*7c478bd9Sstevel@tonic-gateuse Sun::Solaris::Project qw(:ALL :PRIVATE); 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate# 43*7c478bd9Sstevel@tonic-gate# Print a usage message and exit. 44*7c478bd9Sstevel@tonic-gate# 45*7c478bd9Sstevel@tonic-gatesub usage 46*7c478bd9Sstevel@tonic-gate{ 47*7c478bd9Sstevel@tonic-gate my (@msg) = @_; 48*7c478bd9Sstevel@tonic-gate my $prog = basename($0); 49*7c478bd9Sstevel@tonic-gate my $space = ' ' x length($prog); 50*7c478bd9Sstevel@tonic-gate print(STDERR "$prog: @msg\n") if (@msg); 51*7c478bd9Sstevel@tonic-gate printf(STDERR gettext( 52*7c478bd9Sstevel@tonic-gate " %s [-n] [-f filename] [-p projid [-o]] [-c comment]\n". 53*7c478bd9Sstevel@tonic-gate " %s [-U user[,user...]] [-G group[,group...]]\n". 54*7c478bd9Sstevel@tonic-gate " %s [-K name[=value[,value...]]] project\n"), 55*7c478bd9Sstevel@tonic-gate $prog, $space, $space); 56*7c478bd9Sstevel@tonic-gate exit(2); 57*7c478bd9Sstevel@tonic-gate} 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate# 60*7c478bd9Sstevel@tonic-gate# Print a list of error messages and exit. 61*7c478bd9Sstevel@tonic-gate# 62*7c478bd9Sstevel@tonic-gatesub error 63*7c478bd9Sstevel@tonic-gate{ 64*7c478bd9Sstevel@tonic-gate my $exit = $_[0][0]; 65*7c478bd9Sstevel@tonic-gate my $prog = basename($0) . ': '; 66*7c478bd9Sstevel@tonic-gate foreach my $err (@_) { 67*7c478bd9Sstevel@tonic-gate my ($e, $fmt, @args) = @$err; 68*7c478bd9Sstevel@tonic-gate printf(STDERR $prog . $fmt . "\n", @args); 69*7c478bd9Sstevel@tonic-gate } 70*7c478bd9Sstevel@tonic-gate exit($exit); 71*7c478bd9Sstevel@tonic-gate} 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate# 74*7c478bd9Sstevel@tonic-gate# Main routine of script. 75*7c478bd9Sstevel@tonic-gate# 76*7c478bd9Sstevel@tonic-gate# Set the message locale. 77*7c478bd9Sstevel@tonic-gate# 78*7c478bd9Sstevel@tonic-gatesetlocale(LC_ALL, ''); 79*7c478bd9Sstevel@tonic-gatetextdomain(TEXT_DOMAIN); 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate# Process command options and do some initial command-line validity checking. 83*7c478bd9Sstevel@tonic-gatemy ($pname, $flags); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gatemy $projfile = &PROJF_PATH; 86*7c478bd9Sstevel@tonic-gatemy $opt_n; 87*7c478bd9Sstevel@tonic-gatemy $opt_c; 88*7c478bd9Sstevel@tonic-gatemy $opt_o; 89*7c478bd9Sstevel@tonic-gatemy $opt_p; 90*7c478bd9Sstevel@tonic-gatemy $opt_U; 91*7c478bd9Sstevel@tonic-gatemy $opt_G; 92*7c478bd9Sstevel@tonic-gatemy @opt_K; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gateGetOptions("f=s" => \$projfile, 95*7c478bd9Sstevel@tonic-gate "n" => \$opt_n, 96*7c478bd9Sstevel@tonic-gate "c=s" => \$opt_c, 97*7c478bd9Sstevel@tonic-gate "o" => \$opt_o, 98*7c478bd9Sstevel@tonic-gate "p=s" => \$opt_p, 99*7c478bd9Sstevel@tonic-gate "U=s" => \$opt_U, 100*7c478bd9Sstevel@tonic-gate "G=s" => \$opt_G, 101*7c478bd9Sstevel@tonic-gate "K=s" => \@opt_K) || usage(); 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gateusage(gettext('Invalid command-line arguments')) if (@ARGV != 1); 104*7c478bd9Sstevel@tonic-gateusage(gettext('No project name specified')) if (! defined($ARGV[0])); 105*7c478bd9Sstevel@tonic-gateusage(gettext('-o requires -p projid to be specified')) 106*7c478bd9Sstevel@tonic-gate if (defined($opt_o) && ! defined($opt_p)); 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate$pname = $ARGV[0]; 109*7c478bd9Sstevel@tonic-gatemy $maxpjid = 99; 110*7c478bd9Sstevel@tonic-gatemy $tmpprojf; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate# Fabricate an unique temporary filename. 114*7c478bd9Sstevel@tonic-gate$tmpprojf = $projfile . ".tmp.$$"; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gatemy $pfh; 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gateif (defined($opt_n)) { 119*7c478bd9Sstevel@tonic-gate $flags->{'validate'} = 'false'; 120*7c478bd9Sstevel@tonic-gate} else { 121*7c478bd9Sstevel@tonic-gate $flags->{'validate'} = 'true'; 122*7c478bd9Sstevel@tonic-gate} 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate$flags->{'res'} = 'true'; 125*7c478bd9Sstevel@tonic-gate$flags->{'dup'} = 'true'; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gatemy $pf; 128*7c478bd9Sstevel@tonic-gatemy ($mode, $uid, $gid); 129*7c478bd9Sstevel@tonic-gatemy $tmperr; 130*7c478bd9Sstevel@tonic-gatemy $ret; 131*7c478bd9Sstevel@tonic-gatemy $err; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate# Read the project file. sysopen() is used so we can control the file mode. 134*7c478bd9Sstevel@tonic-gateif (! sysopen($pfh, $projfile, O_RDONLY)) { 135*7c478bd9Sstevel@tonic-gate if ($! == Errno::ENOENT) { 136*7c478bd9Sstevel@tonic-gate $pf = []; 137*7c478bd9Sstevel@tonic-gate $mode = 0644; 138*7c478bd9Sstevel@tonic-gate $uid = getuid(); 139*7c478bd9Sstevel@tonic-gate $gid = getgid(); 140*7c478bd9Sstevel@tonic-gate } else { 141*7c478bd9Sstevel@tonic-gate error([10, gettext('Cannot open %s: %s'), $projfile, $!]); 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate} else { 144*7c478bd9Sstevel@tonic-gate ($mode, $uid, $gid) = (stat($pfh))[2,4,5]; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate ($ret, $pf) = projf_read($pfh, $flags); 147*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 148*7c478bd9Sstevel@tonic-gate error(@$pf); 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate close($pfh); 151*7c478bd9Sstevel@tonic-gate foreach (@$pf) { 152*7c478bd9Sstevel@tonic-gate $maxpjid = $_->{'projid'} if ($_->{'projid'} > $maxpjid); 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate} 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gatemy $proj = {}; 158*7c478bd9Sstevel@tonic-gatemy ($value, $list); 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate$proj->{'name'} = ''; 161*7c478bd9Sstevel@tonic-gate$proj->{'projid'} = $maxpjid + 1;; 162*7c478bd9Sstevel@tonic-gate$proj->{'comment'} = ''; 163*7c478bd9Sstevel@tonic-gate$proj->{'userlist'} = []; 164*7c478bd9Sstevel@tonic-gate$proj->{'grouplist'} = []; 165*7c478bd9Sstevel@tonic-gate$proj->{'attributelist'} = []; 166*7c478bd9Sstevel@tonic-gate$proj->{'modified'} = 'true'; 167*7c478bd9Sstevel@tonic-gatepush(@$pf, $proj); 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate# Update the record as appropriate. 170*7c478bd9Sstevel@tonic-gate$err = []; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate($ret, $value) = projent_parse_name($pname); 173*7c478bd9Sstevel@tonic-gateif ($ret != 0) { 174*7c478bd9Sstevel@tonic-gate push(@$err, @$value); 175*7c478bd9Sstevel@tonic-gate} else { 176*7c478bd9Sstevel@tonic-gate $proj->{'name'} = $value; 177*7c478bd9Sstevel@tonic-gate if (!defined($opt_n)) { 178*7c478bd9Sstevel@tonic-gate ($ret, $tmperr) = 179*7c478bd9Sstevel@tonic-gate projent_validate_unique_name($proj, $pf); 180*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 181*7c478bd9Sstevel@tonic-gate push(@$err, @$tmperr); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate} 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate# Apply any changes due to options. 187*7c478bd9Sstevel@tonic-gateif (defined($opt_p)) { 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate my ($ret, $value) = projent_parse_projid($opt_p); 190*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 191*7c478bd9Sstevel@tonic-gate push(@$err, @$value); 192*7c478bd9Sstevel@tonic-gate } else { 193*7c478bd9Sstevel@tonic-gate $proj->{'projid'} = $value; 194*7c478bd9Sstevel@tonic-gate if (!defined($opt_n)) { 195*7c478bd9Sstevel@tonic-gate ($ret, $tmperr) = 196*7c478bd9Sstevel@tonic-gate projent_validate_projid($value, {}); 197*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 198*7c478bd9Sstevel@tonic-gate push(@$err, @$tmperr); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate if ((!defined($opt_n)) && (!defined($opt_o))) { 202*7c478bd9Sstevel@tonic-gate ($ret, $tmperr) = 203*7c478bd9Sstevel@tonic-gate projent_validate_unique_id($proj, $pf); 204*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 205*7c478bd9Sstevel@tonic-gate push(@$err, @$tmperr); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate} 210*7c478bd9Sstevel@tonic-gateif (defined($opt_c)) { 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate my ($ret, $value) = projent_parse_comment($opt_c); 213*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 214*7c478bd9Sstevel@tonic-gate push(@$err, @$value); 215*7c478bd9Sstevel@tonic-gate } else { 216*7c478bd9Sstevel@tonic-gate $proj->{'comment'} = $value; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate} 219*7c478bd9Sstevel@tonic-gateif (defined($opt_U)) { 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate my @sortlist; 222*7c478bd9Sstevel@tonic-gate my ($ret, $list) = projent_parse_users($opt_U, 223*7c478bd9Sstevel@tonic-gate { 'allowspaces' => 1 }); 224*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 225*7c478bd9Sstevel@tonic-gate push(@$err, @$list); 226*7c478bd9Sstevel@tonic-gate } else { 227*7c478bd9Sstevel@tonic-gate @sortlist = sort(@$list); 228*7c478bd9Sstevel@tonic-gate $proj->{'userlist'} = \@sortlist; 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate} 231*7c478bd9Sstevel@tonic-gateif (defined($opt_G)) { 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate my @sortlist; 234*7c478bd9Sstevel@tonic-gate my ($ret, $list) = projent_parse_groups($opt_G, 235*7c478bd9Sstevel@tonic-gate { 'allowspaces' => 1 }); 236*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 237*7c478bd9Sstevel@tonic-gate push(@$err, @$list); 238*7c478bd9Sstevel@tonic-gate } else { 239*7c478bd9Sstevel@tonic-gate @sortlist = sort(@$list); 240*7c478bd9Sstevel@tonic-gate $proj->{'grouplist'} = \@sortlist; 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate} 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gatemy $attrib; 245*7c478bd9Sstevel@tonic-gatemy @attriblist; 246*7c478bd9Sstevel@tonic-gatemy @sortlist; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate# Support multiple instances of -K. 249*7c478bd9Sstevel@tonic-gateforeach $attrib (@opt_K) { 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate my ($ret, $list) = projent_parse_attributes($attrib, 252*7c478bd9Sstevel@tonic-gate {'allowunits' => 1}); 253*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 254*7c478bd9Sstevel@tonic-gate push(@$err, @$list); 255*7c478bd9Sstevel@tonic-gate } else { 256*7c478bd9Sstevel@tonic-gate push(@attriblist, @$list); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate} 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gateif (@attriblist) { 261*7c478bd9Sstevel@tonic-gate @sortlist = sort { $a->{'name'} cmp $b->{'name'} } @attriblist; 262*7c478bd9Sstevel@tonic-gate $proj->{'attributelist'} = \@sortlist; 263*7c478bd9Sstevel@tonic-gate} 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate# Validate project entry changes. 266*7c478bd9Sstevel@tonic-gateif (!defined($opt_n)) { 267*7c478bd9Sstevel@tonic-gate ($ret, $tmperr) = projent_validate($proj, $flags); 268*7c478bd9Sstevel@tonic-gate if ($ret != 0) { 269*7c478bd9Sstevel@tonic-gate push(@$err, @$tmperr); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate} 272*7c478bd9Sstevel@tonic-gateif (@$err) { 273*7c478bd9Sstevel@tonic-gate error(@$err); 274*7c478bd9Sstevel@tonic-gate} 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate# Write out the project file. 277*7c478bd9Sstevel@tonic-gateumask(0000); 278*7c478bd9Sstevel@tonic-gatesysopen($pfh, $tmpprojf, O_WRONLY | O_CREAT | O_EXCL, $mode) || 279*7c478bd9Sstevel@tonic-gate error([10, gettext('Cannot create %s: %s'), $tmpprojf, $!]); 280*7c478bd9Sstevel@tonic-gateprojf_write($pfh, $pf); 281*7c478bd9Sstevel@tonic-gateclose($pfh); 282*7c478bd9Sstevel@tonic-gateif (!chown($uid, $gid, $tmpprojf)) { 283*7c478bd9Sstevel@tonic-gate unlink($tmpprojf); 284*7c478bd9Sstevel@tonic-gate error([10, gettext('Cannot set ownership of %s: %s'), 285*7c478bd9Sstevel@tonic-gate $tmpprojf, $!]); 286*7c478bd9Sstevel@tonic-gate} 287*7c478bd9Sstevel@tonic-gateif (! rename($tmpprojf, $projfile)) { 288*7c478bd9Sstevel@tonic-gate unlink($tmpprojf); 289*7c478bd9Sstevel@tonic-gate error([10, gettext('cannot rename %s to %s: %s'), 290*7c478bd9Sstevel@tonic-gate $tmpprojf, $projfile, $!]); 291*7c478bd9Sstevel@tonic-gate} 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gateexit(0); 294