Unleashed v1.4
[unleashed.git] / usr / src / cmd / projadd / projadd.pl
blob04ce7143b21d007b5cda540bc5bb96b43d06e39b
1 #!/usr/perl5/bin/perl -w
3 # CDDL HEADER START
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.
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.
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]
21 # CDDL HEADER END
24 # Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
27 #ident "%Z%%M% %I% %E% SMI"
30 require 5.005;
31 use strict;
32 use locale;
33 use Errno;
34 use Fcntl;
35 use File::Basename;
36 use Getopt::Std;
37 use Getopt::Long qw(:config no_ignore_case bundling);
38 use POSIX qw(locale_h getuid getgid);
39 use Sun::Solaris::Utils qw(textdomain gettext);
40 use Sun::Solaris::Project qw(:ALL :PRIVATE);
43 # Print a usage message and exit.
45 sub usage
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);
60 # Print a list of error messages and exit.
62 sub error
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);
70 exit($exit);
74 # Main routine of script.
76 # Set the message locale.
78 setlocale(LC_ALL, '');
79 textdomain(TEXT_DOMAIN);
82 # Process command options and do some initial command-line validity checking.
83 my ($pname, $flags);
85 my $projfile = &PROJF_PATH;
86 my $opt_n;
87 my $opt_c;
88 my $opt_o;
89 my $opt_p;
90 my $opt_U;
91 my $opt_G;
92 my @opt_K;
94 GetOptions("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();
103 usage(gettext('Invalid command-line arguments')) if (@ARGV != 1);
104 usage(gettext('No project name specified')) if (! defined($ARGV[0]));
105 usage(gettext('-o requires -p projid to be specified'))
106 if (defined($opt_o) && ! defined($opt_p));
108 $pname = $ARGV[0];
109 my $maxpjid = 99;
110 my $tmpprojf;
113 # Fabricate an unique temporary filename.
114 $tmpprojf = $projfile . ".tmp.$$";
116 my $pfh;
118 if (defined($opt_n)) {
119 $flags->{'validate'} = 'false';
120 } else {
121 $flags->{'validate'} = 'true';
124 $flags->{'res'} = 'true';
125 $flags->{'dup'} = 'true';
127 my $pf;
128 my ($mode, $uid, $gid);
129 my $tmperr;
130 my $ret;
131 my $err;
133 # Read the project file. sysopen() is used so we can control the file mode.
134 if (! 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, $!]);
143 } else {
144 ($mode, $uid, $gid) = (stat($pfh))[2,4,5];
146 ($ret, $pf) = projf_read($pfh, $flags);
147 if ($ret != 0) {
148 error(@$pf);
150 close($pfh);
151 foreach (@$pf) {
152 $maxpjid = $_->{'projid'} if ($_->{'projid'} > $maxpjid);
157 my $proj = {};
158 my ($value, $list);
160 $proj->{'name'} = '';
161 $proj->{'projid'} = $maxpjid + 1;;
162 $proj->{'comment'} = '';
163 $proj->{'userlist'} = [];
164 $proj->{'grouplist'} = [];
165 $proj->{'attributelist'} = [];
166 $proj->{'modified'} = 'true';
167 push(@$pf, $proj);
169 # Update the record as appropriate.
170 $err = [];
172 ($ret, $value) = projent_parse_name($pname);
173 if ($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);
186 # Apply any changes due to options.
187 if (defined($opt_p)) {
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);
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);
210 if (defined($opt_c)) {
212 my ($ret, $value) = projent_parse_comment($opt_c);
213 if ($ret != 0) {
214 push(@$err, @$value);
215 } else {
216 $proj->{'comment'} = $value;
219 if (defined($opt_U)) {
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;
231 if (defined($opt_G)) {
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;
244 my $attrib;
245 my @attriblist;
246 my @sortlist;
248 # Support multiple instances of -K.
249 foreach $attrib (@opt_K) {
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);
260 if (@attriblist) {
261 @sortlist = sort { $a->{'name'} cmp $b->{'name'} } @attriblist;
262 $proj->{'attributelist'} = \@sortlist;
265 # Validate project entry changes.
266 if (!defined($opt_n)) {
267 ($ret, $tmperr) = projent_validate($proj, $flags);
268 if ($ret != 0) {
269 push(@$err, @$tmperr);
272 if (@$err) {
273 error(@$err);
276 # Write out the project file.
277 umask(0000);
278 sysopen($pfh, $tmpprojf, O_WRONLY | O_CREAT | O_EXCL, $mode) ||
279 error([10, gettext('Cannot create %s: %s'), $tmpprojf, $!]);
280 projf_write($pfh, $pf);
281 close($pfh);
282 if (!chown($uid, $gid, $tmpprojf)) {
283 unlink($tmpprojf);
284 error([10, gettext('Cannot set ownership of %s: %s'),
285 $tmpprojf, $!]);
287 if (! rename($tmpprojf, $projfile)) {
288 unlink($tmpprojf);
289 error([10, gettext('cannot rename %s to %s: %s'),
290 $tmpprojf, $projfile, $!]);
293 exit(0);