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