From 78f98960e4399be8650b51b28070203ea8dc6168 Mon Sep 17 00:00:00 2001 From: "Jordan K. Hubbard" Date: Mon, 9 Jan 1995 11:26:31 +0000 Subject: Wolfram Schneider : o manpage o save configuration in /etc/adduser.conf o send message file (/etc/adduser.message) Submitted by: woschcs.tu-berlin.de --- adduser/adduser.8 | 169 ++++++++++++-- adduser/adduser.perl | 634 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 680 insertions(+), 123 deletions(-) (limited to 'adduser') diff --git a/adduser/adduser.8 b/adduser/adduser.8 index 6ed7fb6..eb2ae8f 100644 --- a/adduser/adduser.8 +++ b/adduser/adduser.8 @@ -1,26 +1,163 @@ -.Dd January 3, 1994 -.Dt ADDUSER 8 -.Os FreeBSD +.\" +.\" (c) Copyright 1995 Wolfram Schneider. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Wolfram Schneider +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" /usr/sbin/adduser - add new user(s) +.\" +.\" Bugs: sure (my english!) +.\" Email: Wolfram Schneider +.\" +.\" $Id: adduser.8,v 1.4 1995/01/08 17:40:20 w Exp w $ +.\" +.Dd Jan, 9, 1995 +.Dt ADDUSER 8 +.Os FreeBSD 2.1 .Sh NAME .Nm adduser - -.Sh SYNOPSIS -.Nm +.Nd command for adding new users .Sh DESCRIPTION +.Nm Adduser +is a simple program for adding new users. Adduser check +passwd, group and shell database. It create passwd/group entry, +HOME-directory, dotfiles and send new user a welcome message. + +.Sh RESTRICTION +.Bl -tag -width Ds -compact +.It Sy username +Login name. Only lowercase characters or digits. +.It Sy fullname +Firstname an surname. +.Ql Pa \: +not allowed. +.It Sy shell +Only valid shells from shell database. +.It Sy uid +Automatic generated. +.It Sy gid +Automatic generated. Gid and uid are equal (if possible). Groupname +is the same as username. +.El + +.Sh CONFIGURATION +.Bl -tag -width Ds -compact +.It Sy 1. +Read intern variables. +.It Sy 2. +Read config file (/etc/adduser.conf) +.It Sy 3. +Parse command line options +.El + +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl help +Print options and exit. +.It Fl silent +Few warnings, question, bugreports. +.It Fl verbose +Many warning, question. Recommended for noivice users. +.It Fl debug +Debuging. +.It Fl noconfig +Do not read config file. +.It Fl home Ar partition +Default home partition where all users located. +.It Fl shell Ar shell +Default shell for new users. +.It Fl dotdir Ar directory +Copy files from .Ar directory into the HOME-directory of new users. +.Ql Pa dot.foo +files renamed to +.Ql Pa .foo +Don't copy files if +.Ar directory +equal with +.Ar no +.It Fl message Ar file +Send new users a welcome message. +Don't send message if +.Ar file +equal with +.Ar no +.It Fl create_conf +Create new config and message file and exit. + +.Sh FORMATS +.Bl -tag -width Ds -compact +.Ql Pa # +is a commemt. + +.P +.It Sy config file .Nm Adduser -is a perl script for adding users to the system. Still awaiting -a man page entry for it but for now you can probably get away with just -typing -.Nm adduser -and filling in the blanks. +read and write this file. +See /etc/adduser.conf for more details. +.It Sy message file +Eval variables in this file. See /etc/adduser.message for more +details. +.El + .Sh FILES -Beats me. Wolfram? Man page please! :-) +.Bl -tag -width /etc/master.passwdxx -compact +.It Pa /etc/master.passwd +user database +.It Pa /etc/group +group database +.It Pa /etc/shells +shell database +.It Pa /etc/adduser.conf +config file for adduser +.It Pa /etc/adduser.message +message file for adduser +.It Pa /usr/share/skel +skeletal login directory +.It Pa /var/log/adduser +logfile for adduser +.El + .Sh SEE ALSO -.Xr pwd_mkdb 8 -.Xr perl 1 +.Xr chpass 1 , +.Xr finger 1 , +.Xr passwd 1 , +.Xr aliases 5 , +.Xr passwd 5 , +.Xr group 5 , +.Xr shells 5 , +.Xr pwd_mkdb 8 , +.Xr vipw 8 + +.\" .Sh BUGS .Sh HISTORY -The adduser command first appeared in FreeBSD 2.0C (12-94) by Gary Clark, II. -This newer version was submitted by Wolfram Schneider. +The +.Nm +command appeared in FreeBSD 2.1 + +.\" .Sh AUTHOR +.\" Wolfram Schneider, Berlin diff --git a/adduser/adduser.perl b/adduser/adduser.perl index 60e89e7..ca07f30 100644 --- a/adduser/adduser.perl +++ b/adduser/adduser.perl @@ -12,7 +12,7 @@ # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: -# This product includes software developed by Wolfram Schneider +# This product includes software developed by Wolfram Schneider # 4. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission # @@ -32,33 +32,45 @@ # Bugs: sure (my english!) # Email: Wolfram Schneider # -# $Id: adduser,v 1.17 1995/01/02 00:08:43 w Exp w $ +# $Id: adduser,v 1.40 1995/01/08 17:40:09 w Exp w $ # +# read variables sub variables { - $verbose = 1; - $batch = 0; # batch mode - $defaultpasswd = 0; - $dotdir = "/usr/share/skel"; - - if (1) { - $home = "/home"; - $shells = "/etc/shells"; - $passwd = "/etc/master.passwd"; + $verbose = 1; # verbose = [0-2] + $defaultpasswd = "no"; # use password for new users + $dotdir = "/usr/share/skel"; # copy dotfiles from this dir + $send_message = "/etc/adduser.message"; # send message to new user + $config = "/etc/adduser.conf"; # config file for adduser + $config_read = 1; # read config file + $logfile = "/var/log/adduser"; # logfile + $home = "/home"; # default HOME + $etc_shells = "/etc/shells"; + $etc_passwd = "/etc/master.passwd"; $group = "/etc/group"; - $pwd_mkdb = "pwd_mkdb -p"; - } else { + $pwd_mkdb = "pwd_mkdb -p"; # program for building passwd database + + if ($test) { $home = "/home/w/tmp/adduser/home"; - $shells = "./shells"; - $passwd = "./master.passwd"; + $etc_shells = "./shells"; + $etc_passwd = "./master.passwd"; $group = "./group"; $pwd_mkdb = "pwd_mkdb -p -d ."; + $config = "adduser.conf"; + $send_message = "./adduser.message"; + $logfile = "./log.adduser"; } + $ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin"; + # List of directories where shells located @path = ('/bin', '/usr/bin', '/usr/local/bin'); + # common shells, first element has higher priority @shellpref = ('bash', 'tcsh', 'ksh', 'csh', 'sh'); + + $defaultshell = 'bash'; # defaultshell if not empty + $uid_start = 1000; # new users get this uid - $uid_end = 32000; + $uid_end = 32000; # max. uid # global variables $username = ''; # $username{username} = uid @@ -66,15 +78,16 @@ sub variables { $pwgid = ''; # $pwgid{pwgid} = username; gid from passwd db $groupname =''; # $groupname{groupname} = gid $gid = ''; # $gid{gid} = groupname; gid form group db - $defaultshell = ''; @passwd_backup = ''; + @message_buffer = ''; + @user_variable_list = ''; # user variables in /etc/adduser.conf + $do_not_delete = '## DO NOT DELETE THIS LINE!'; } -# read shell database -# See also: shells(5) +# read shell databasem, see also: shells(5) sub shells_read { local($s, @dummy); - open(S, $shells) || die "$shells:$!\n"; + open(S, $etc_shells) || die "$shells:$!\n"; while() { if (/^[ \t]*\//) { ($s, @dummy) = split; @@ -90,83 +103,128 @@ sub shells_read { # add new/local shells sub shells_add { local($e,$dir,@list); + foreach $e (@shellpref) { if (!$shell{$e}) { foreach $dir (@path) { if (-x "$dir/$e") { - push(@list, "$dir/$e") if - &confirm_yn("Found shell: $dir/$e. Add to $shells?", "yes"); + if ($verbose) { + if (&confirm_yn("Found shell: $dir/$e. Add to $etc_shells?", "yes")) { + push(@list, "$dir/$e"); + push(@shellpref, "$dir/$e"); + $shell{&basename("$dir/$e")} = "$dir/$e"; + $changes++; + } + } else { + print "Found unused shell: $dir/$e\n"; + } } } } } - if ($#list >= 0) { - foreach $e (@list) { - $shell{&basename($e)} = $e; - #print "$e\n"; - } - &append_file($shells, @list); - } + &append_file($etc_shells, @list) if $#list >= 0; } -# choise your favourite shell -sub shells_pref { +# choise your favourite shell an return the shell +sub shell_default { local($e,$i,$s); + local($sh) = $defaultshell; + + # $defaultshell is empty, looking for another shell + if (!$sh || !$shell{$sh}) { + $i = 0; + while($i < $#shellpref) { + last if $shell{$shellpref[$i]}; + $i++; + } + $sh = $shellpref[$i]; - $i = 0; - while($i < $#shellpref) { - last if $shell{$shellpref[$i]}; - $i++; + if (!$sh || !$shell{$sh}) { + warn "No valid shell found in $etc_shells.\n"; + $sh = ''; + } + } + if ($verbose) { + $s = &confirm_list("Enter your default shell:", 0, + $sh, sort(keys %shell)); + print "Your default shell is: $s -> $shell{$s}\n"; + $changes++ if $s ne $sh; + return $s; + } else { + return $sh; } - $s = &confirm_list("Enter Your default shell:", 0, - $shellpref[$i], sort(keys %shell)); - print "Your default shell is: $s -> $shell{$s}\n" if $verbose; - $defaultshell = $s; } -# return default home partition +# return default home partition, create base directory if nesseccary sub home_partition { local($h); + $oldverbose = $verbose if !defined $oldverbose; + + if ($verbose) { + $h = &confirm_list("Enter your default HOME partition:", 1, $home, ""); + } else { + $h = $home; + } + + if ($h !~ "^/") { + warn "Please use absolute path for home: ``$h''.\n"; + $verbose++; + $h =~ s|^[^/]+||; + $home = $h; + return &home_partition; + } - $h = &confirm_list("Enter Your default HOME partition:", 1, $home, ""); - if (-e "$h") { + if (-e $h) { if (!(-d _ || -l $h)) { warn "$h exist, but is it not a directory or symlink!\n"; + $verbose++; return &home_partition; } if (! -w _) { warn "$h is not writable!\n"; + $verbose++; return &home_partition; } } else { + $verbose++; return &home_partition unless &mkdirhier($h); } - - $home = $h; + + $verbose = $oldverbose; + undef $oldverbose; + $changes++ if $h ne $home; return $h; } # check for valid passwddb sub passwd_check { - print "Check $passwd\n" if $verbose > 0; - system("$pwd_mkdb $passwd"); - die "\nInvalid $passwd - cannot add any users!\n" if $?; + print "Check $etc_passwd\n" if $verbose > 0; + system("$pwd_mkdb $etc_passwd"); + die "\nInvalid $etc_passwd - cannot add any users!\n" if $?; } # read /etc/passwd sub passwd_read { - local($un, $pw, $ui, $gi); + local($un, $pw, $ui, $gi, $sh, %shlist); - open(P, "$passwd") || die "$passwd: $!\n"; + print "Check $group\n" if $verbose; + foreach $sh (keys %shell) { + $shlist{$shell{$sh}} = $sh; #print "$sh $shell{$sh}\n"; + } + + open(P, "$etc_passwd") || die "$passwd: $!\n"; while(

) { chop; push(@passwd_backup, $_); - ($un, $pw, $ui, $gi) = (split(/:/, $_))[0..3]; + ($un, $pw, $ui, $gi, $sh) = (split(/:/, $_))[0..3,9]; print "$un already exist with uid: $username{$un}!\n" if $username{$un}; $username{$un} = $ui; print "User $un: uid $ui exist twice: $uid{$ui}\n" - if $uid{$ui} && $verbose; + if $uid{$ui} && $verbose && $ui; # don't warn for uid 0 + print "User $un: illegal shell: ``$sh''\n" + if ((!$shlist{$sh} && $sh) && + ($un !~ /^(bin|uucp|falcon|nobody)$/)); $uid{$ui} = $un; $pwgid{$gi} = $un; } @@ -197,31 +255,35 @@ sub group_check { foreach $e (keys %pwgid) { if (!$gid{$e}) { $user = $pwgid{$e}; - warn "Gid $e is defined in $passwd for user ``$user''\n"; - warn "but not in $group!\n"; + warn "User ``$user'' has gid $e but a group with this " . + "gid does not exist.\n"; + #warn "Gid $e is defined in $etc_passwd for user ``$user''\n"; + #warn "but not in $group!\n"; if ($groupname{$user}) { warn < $groupname{$user}) for user ``$user'' -in $passwd & $group are wrong. -See $passwd ``$user:*:$username{$user}:$e'' -See $group ``$user:*:$groupname{$user}'' +Maybe the gids ($e <-> $groupname{$user}) for user+group ``$user'' are wrong. EOF } else { push(@list, "$user:*:$e:$user") - if (&confirm_yn("Add group``$user'' gid $e to $group?", "y")); + if $verbose && + &confirm_yn("Add group``$user'' gid $e to $group?", "y"); } } } &append_file($group, @list) if $#list >= 0; } +# +# main loop for creating new users +# sub new_users { local(@userlist) = @_; local($name); local($defaultname) = "a-z0-9"; - print "\nOk, let's go.\n"; - print "Don't worry about mistakes. I ask You later for " . + print "\n" if $verbose; + print "Ok, let's go.\n" . + "Don't worry about mistakes. I ask you later for " . "correct input.\n" if $verbose; while(1) { @@ -246,10 +308,10 @@ sub new_users { print < $crash") || die "Sorry, give up\n"; @@ -272,7 +334,7 @@ EOF system("$pwd_mkdb $crash"); die "Sorry, give up\n" if $?; - die "Successfully restore $passwd. Exit.\n"; + die "Successfully restore $etc_passwd. Exit.\n"; } # Add new group &append_file($group, "$name:*:$g_id:$name") @@ -287,32 +349,64 @@ EOF $gid{$g_id} = $name; print "Added user ``$name''\n"; + + if ($send_message && $send_message ne "no") { + local($m) = &confirm_list("Send message to ``$name'' and:", + 1, "no", ("second_mail_address", "no")); + if ($verbose) { + print "send message to: ``$name''"; + if ($m eq "no") { print "\n" } + else { print " and ``$m''\n"} + } + $m = "" if $m eq "no"; + local($e); + if (!open(M, "| mail -s Welcome $name $m")) { + warn "Cannot send mail to: $name $m!\n"; + } else { + foreach $e (@message_buffer) { + print M eval "\"$e\""; + } + close M; + } + } + local($a) = &confirm_yn("Change password", $defaultpasswd); - if (($a && $defaultpasswd) || (!$a && !$defaultpasswd)) { + local($empty_password) = ""; + if (($a && $defaultpasswd ne "no" && $defaultpasswd) || + (!$a && $defaultpasswd eq "no")) { while(1) { system("passwd $name"); - last unless $?; + if (!$?) { $empty_password = "*"; last } last unless &confirm_yn("Passwd $name failed. Try again?", "yes"); } } - &home_create($name); - } - if (&confirm_yn("Continue with next user?", "yes")) { - &new_users; + &adduser_log("$name:$empty_password:$u_id:$g_id($name):$fullname"); + &home_create($name); + } + if (&confirm_yn("Continue with next user?", "yes")) { + print "\n" if !$verbose; + &new_users; } else { print "Good by.\n" if $verbose; } } -# -sub password_pref { - $defaultpasswd = !&confirm_yn("Use empty passwords", "yes"); +# ask for password usage +sub password_default { + local($p) = $defaultpasswd; + if ($verbose) { + $p = &confirm_yn("Use passwords", $defaultpasswd); + $changes++ unless $p; + } + return "yes" if (($defaultpasswd eq "yes" && $p) || + ($defaultpasswd eq "no" && !$p)); + return "no"; # otherwise } # misc sub check_root { - die "You are not root!\n" if $<; + die "You are not root!\n" if $< && !$test; } sub usage { @@ -324,13 +418,35 @@ OPTIONS: -help this help -silent opposite of verbose -verbose verbose +-debug verbose verbose +-noconfig don't read config-file -home home default HOME partition [$home] --shell shell default SHELL --dotdir dir copy files from dir, default $dotdir +-shell shell default SHELL [$defaultshell] +-dotdir dir copy files from dir, default [$dotdir] +-message file send message to new users [$send_message] +-create_conf create configuration/message file and exit USAGE exit 1; } +# print banner +sub copyright { + print < +EOF +} + +# hints +sub hints { + if ($verbose) { + print "Use option ``-silent'' if you don't want see " . + "some warnings & questions.\n\n"; + } else { + print "Use option ``-verbose'' if you want see more warnings & " . + "questions \nor try to repair bugs.\n\n"; + } +} + # sub parse_arguments { local(@argv) = @_; @@ -338,14 +454,19 @@ sub parse_arguments { while ($_ = $argv[0], /^-/) { shift @argv; last if /^--$/; - if (/^--?(debug|verbose)$/) { $verbose = 1 } - elsif (/^--?(silent|guru|wizard)$/) { $verbose = 0 } - elsif (/^--?(verbose)$/) { $verbose = 1 } + if (/^--?(verbose)$/) { $verbose = 1 } + elsif (/^--?(silent|guru|wizard|quit)$/) { $verbose = 0 } + elsif (/^--?(debug)$/) { $verbose = 2 } elsif (/^--?(h|help|\?)$/) { &usage } elsif (/^--?(home)$/) { $home = $argv[0]; shift @argv } - elsif (/^--?(shell)$/) { $shell = $argv[0]; shift @argv } + elsif (/^--?(shell)$/) { $defaultshell = $argv[0]; + shift @argv } elsif (/^--?(dotdir)$/) { $dotdir = $argv[0]; shift @argv } - elsif (/^--?(batch)$/) { $batch = 1; } + elsif (/^--?(message)$/) { $send_message = $argv[0]; shift @argv; + $sendmessage = 1; } + # see &config_read + elsif (/^--?(create_conf)$/) { &create_conf; } + elsif (/^--?(noconfig)$/) { $config_read = 0; } else { &usage } } #&usage if $#argv < 0; @@ -357,19 +478,68 @@ sub basename { return $name; } -# +sub dirname { + local($name) = @_; + $name =~ s|[/]+$||; # delete any / at end + $name =~ s|[^/]+$||; + $name = "/" unless $name; # dirname of / is / + return $name; +} + +# return 1 if $file is a readable file or link +sub filetest { + local($file, $verb) = @_; + + if (-e $file) { + if (-f $file || -l $file) { + return 1 if -r _; + warn "$file unreadable\n" if $verb; + } else { + warn "$file is not a plain file or link\n" if $verb; + } + } + return 0; +} + +# create configuration files and exit +sub create_conf { + $create_conf = 1; + &message_create($send_message); + &config_write(1); + exit(0); +} + +# log for new user in /var/log/adduser +sub adduser_log { + local($string) = @_; + local($e); + + return 1 if $logfile eq "no"; + + local($sec, $min, $hour, $mday, $mon, $year) = localtime; + $mon++; + + foreach $e ('sec', 'min', 'hour', 'mday', 'mon', 'year') { + # '7' -> '07' + eval "\$$e = 0 . \$$e" if (eval "\$$e" < 10); + } + + &append_file($logfile, "$year/$mon/$mday $hour:$min:$sec $string"); +} + +# create HOME directory, copy dotfiles from $dotdir to $HOME sub home_create { local($name) = @_; local(@list); local($e,$from, $to); - print "Create HOME directory\n"; + print "Create HOME directory\n" if $verbose; if(!mkdir("$home/$name", 0755)) { - warn "Cannot create HOME directory for $name: $!\n"; + warn "Cannot create HOME directory for user ``$home/$name'': $!\n"; return 0; } push(@list, "$home/$name"); - if ($dotdir) { + if ($dotdir && $dotdir ne "no") { opendir(D, "$dotdir") || warn "$dotdir: $!\n"; foreach $from (readdir(D)) { if ($from !~ /^(\.|\.\.)$/) { @@ -382,8 +552,8 @@ sub home_create { } closedir D; } - #warn "Chown: $name, $name, @list\n"; - #chown in perl does not work + #warn "Chown: $name, $name, @list\n"; + #chown in perl does not work system("chown $name:$name @list") || warn "$!\n" && return 0; return 1; } @@ -423,10 +593,14 @@ sub mkdirhier { # If !$allow accept only elements from @list. sub confirm_list { local($message, $allow, $confirm, @list) = @_; - local($read, $c); + local($read, $c, $print); + + $print = "$message " if $message; + $print .= "@list "; + print "$print"; + print "\n " if length($print) > 50; + print "[$confirm]: "; - print "$message " if $message; - print "@list [$confirm]: "; chop($read = ); $read =~ s/^[ \t]*//; $read =~ s/[ \t\n]*$//; @@ -441,7 +615,9 @@ sub confirm_list { } # YES or NO question -# $confirm => 'y' or 'n'. Return true if answer 'y' (or 'n') +# return 1 if &confirm("message", "yes") and answer is yes +# or if &confirm("message", "no") an answer is no +# otherwise 0 sub confirm_yn { local($message, $confirm) = @_; local($yes) = "^(yes|YES|y|Y)$"; @@ -472,12 +648,116 @@ sub confirm_yn { } # test if $dotdir exist -sub dotdir_check { - return 1 if -e $dotdir && -r _ && (-d _ || -l $dotdir); - warn "Directory: $dotdir does not exist or unreadable. " . - "Cannot copy dotfiles!\n"; - $dotdir = ''; - return 0; +sub dotdir_default { + #$dotdir = "no" unless $dotdir; + local($dir) = $dotdir; + local($oldverbose) = $verbose; + + if ($dir !~ "^/") { + warn "Please use absulote path for dotdir: ``$dir''\n"; + $dir = "no"; + $verbose++ unless $verbose; + } + while($verbose) { + $dir = &confirm_list("Copy dotfiles from:", 1, + $dir, ("no", $dir)); + last if $dir eq "no"; + last if (-e $dir && -r _ && (-d _ || -l $dir)); + last if !&confirm_yn("Dotdir ``$dir'' is not a dir. Try again", "yes"); + } + unless (-e $dir && -r _ && (-d _ || -l $dir)) { + warn "Directory: $dir does not exist or unreadable.\n" + if $dir ne "no"; + warn "Do not copy dotfiles.\n"; + $dir = "no"; + } + $changes++ if $dir ne $dotdir; + $verbose = $oldverbose; + return $dir; +} + +# ask for messages to new users +sub message_default { + local($file) = $send_message; + local(@d); + + push(@d, $file); + push(@d, "no") if $file ne "no"; + if (!&filetest($file, 1) && $file ne "no") { + if (! -e $file && + &confirm_yn("Create message file ``$file''?", "yes")) { + &message_create($file); + } else { + $file = "no"; + } + } + + while($verbose) { + $file = &confirm_list("Send message from file: ", 1, + $file, @d); + last if $file eq "no"; + if (&filetest($file, 1)) { + last; + } else { + &message_create($file) if ! -e $file && + &confirm_yn("Create ``$file''?", "yes"); + last if &filetest($file, 0); + last if !&confirm_yn( + "File ``$file'' does not exist, try again?", "yes"); + } + } + if ($file eq "no" || !&filetest($file, 0)) { + warn "Do not send message\n" if $verbose; + $file = "no"; + } else { + &message_read($file); + } + + $changes++ if $file ne $send_message; + return $file; +} + +# create message file +sub message_create { + local($file) = @_; + local($dir) = &dirname($file); + + if (! -d $dir) { + return 0 unless &mkdirhier($dir); + } + if (!open(M, "> $file")) { + warn "Messagefile ``$file'': $!\n"; return 0; + } + print M <) { + push(@message_buffer, $_) unless /^[ \t]*#/; + } } # write @list to $file with file-locking @@ -523,6 +803,7 @@ sub next_id { return ($uid_start, $gid_start); } +# cp(1) sub cp { local($from, $to, $tilde) = @_; @@ -552,25 +833,164 @@ sub cp { return 1; } +# read config file +sub config_read { + local($opt) = @_; + local($ev); # evaluate variable or list + local($user_flag) = 0; + + return 1 if $opt =~ /-(noconfig|create_conf)/; # don't read config file + + if ($config_read && -f $config) { + if(!open(C, "$config")) { + warn "$config: $!\n"; return 0; + } + print "Read config file: $config" if $verbose > 1; + while() { + chop; + /^$do_not_delete/ && $user_flag++; + if (/^[ \t]*[a-zA-Z_-]+[ \t]*=/) { + # prepare for evaluating + s/#.*$//; + s/^[ \t]+//; + s/[ \t;]+$//; + s/[ \t]*=[ \t]*/=/; + s/=(.*)/="$1"/ unless /=['"(]/; + + print "$_\n" if $verbose > 1; + if (/=\(/) { # perl list + $ev = "\@"; + } else { # perl variable + $ev = "\$"; + } + eval "$ev$_" || warn "Ignore garbage: $ev $_\n"; + push(@user_variable_list, "$_\n") if $user_flag; + } + } + } +} + +# write config file +sub config_write { + local($silent) = @_; + + if (($changes || ! -e $config || !$config_read) || $silent) { + if (!$silent) { + if (-e $config) { + return 1 if + &confirm_yn("\nWrite your changes to $config?", "no"); + } else { + return 1 unless + &confirm_yn("\nWrite your configuration to $config?", "yes"); + } + } + + local($dir) = &dirname($config); + if (! -d $dir && !&mkdirhier($dir)) { + warn "Cannot save your configuration\n"; + return 0; + } + + if(!open(C, "> $config")) { + warn "$config: $!\n"; return 0; + } + # prepare some variables + $send_message = "no" unless $send_message; + $defaultpasswd = "no" unless $defaultpasswd; + local($shpref) = "'" . join("', '", @shellpref) . "'"; + local($shpath) = "'" . join("', '", @path) . "'"; + local($user_var) = join('', @user_variable_list); + + print C <