1#!/usr/bin/perl
2
3# migrate old samba2 smb.conf settings to new samba3 setup
4# as well as merge local configuration settings
5# Dec 3 2003 Stew Benedict <sbenedict@mandrakesoft.com>
6# revised Jan 6 2004 - dropping some parameters
7# revised Feb 11 2004 - don't try to process a config a second time
8
9# check command line arguments
10my $numargs = @ARGV;
11if ($numargs lt 1) {
12	print "useage: smb-migrate test|test-commit|commit\n";
13	exit(1);
14}
15
16# define some variables
17my $user_parms = 0;
18my $new_conf_file = "/etc/samba/smb.conf";
19my @new_conf;
20my $merged_conf_file = "/etc/samba/smb.conf";
21my $merge_comment = "# *** merged from original smb.conf: ***\n";
22my $uncomment_comment = "# *** uncommented from original smb.conf: ***\n";
23my $unique_comment = "# *** unique added from original smb.conf: ***\n";
24my @merge_log;
25my $log_file = "/var/log/samba/smb-migrate.log";
26my $to_merge = "/etc/samba/smb.conf.tomerge";
27
28if ($ARGV[0] eq "test" || $ARGV[0] eq "test-commit") {
29	$to_merge = "smb.conf"; 
30	$log_file = "smb-migrate.log";
31	$merged_conf_file = "smb.conf.merged";
32}
33
34# if the file has already been processed, don't do it again
35my $processed = `grep -c 'original smb.conf: ***' $to_merge`;
36if ($processed > 0) {
37	`cp $to_merge $new_conf_file`;
38	print "Already processed, aborting.\n";	
39	exit 0;
40}
41	
42# get the stripped, uncommented data from old smb.conf
43my @old_conf = `grep -v "^#" $to_merge | grep -v "^;" | grep -v "^\$"` or die;
44
45# use a clean config file as a starting point
46`cp /usr/share/samba/smb.conf.clean $new_conf_file` if $ARGV[0] !~ /test/;
47
48# and the whole new conf file we're going to merge with
49my @new_conf_org = `cat $new_conf_file` or die;
50
51mlog("Data to change/add in standard sections of smb.conf:\n\n");
52
53sub mlog {
54	my (@dstring) = @_;
55	if ($ARGV[0] eq "test") {
56		print "@dstring";
57	} else {
58		push @merge_log, @dstring;
59	}
60}
61
62sub merge_conf {
63	my ($header, $new_value) = @_;
64	my @parmlist = split " = ", $new_value;
65	my $match = 0;
66	my $comment = '';
67	$comment = $unique_comment if $continuation = 0;
68	$continuation = 1;
69	
70	# find the header in question
71	$index = 0;
72	foreach (@new_conf_org) {
73 		if (/^\[$header\]|;\[$header\]|^; \[$header\]|^\[$header\$\]|;\[$header\$\]|^; \[$header\$\]/) {
74			# restore print$
75			$header = "print" . '$' if $header eq "print";
76			# if the header is commented, remove the comment
77			if (/^;\[|^#\[|^; \[/) {
78				my $entry = $_;
79				@new_conf_org[$index] =~ s/^;|^; |^#//g;
80				mlog("uncomment: $header line $index: $entry -> @new_conf_org[$index]");
81				splice(@new_conf_org, $index, 0, $uncomment_comment);
82				$index++
83			}
84			$start_loc = $index;
85#			print "[$header]: $start_loc\n";
86			last;
87		}
88		$index++
89	}
90	
91	my $elements = @new_conf_org;
92
93	# walk through this header's entries, update as needed
94	for ($i = $start_loc + 1; $i < $elements; $i++) {
95		# if we hit a new header, may be commented - bail out
96		my $is_header = @new_conf_org[$i];
97		$is_header =~ s/^ |\t|\n//;
98		if ($is_header =~ /^\[|;\[|#\[/) { 
99#			print "new header: $is_header at $i\n";
100			if ($match == 0) {
101				# it's possible the parameter is continued across multiple lines
102				$continuation = 0 if  $new_value !~ /\\$/;
103				# completely new entry, try to place it under the correct header
104#				print "new entry for [$header]: $new_value\n";
105				mlog("unique: $header line $last_index: $new_value");
106				splice(@new_conf_org, $last_index + 1, 0, $comment, $new_value);
107				$last_index++;$last_index++;
108			}
109			return;
110		}
111
112		# some syntax changes
113		if ($new_value =~ /winbind/) {
114			$old_value = $new_value; 
115			$new_value =~ s/winbind/idmap/;
116			mlog("syntax: $header: $old_value -> $new_value");
117		}
118
119		# partial match, decide whether to add or replace
120		if (@new_conf_org[$i] =~ /@parmlist[0]/) {
121			if (@new_conf_org[$i] !~ /^;|^#/) {
122				if (@new_conf_org[$i] ne $_) { 
123					mlog("update: $header line $i: @new_conf_org[$i] -> $new_value");
124					@new_conf_org[$i] = ";" . $new_conf_org[$i];
125					splice(@new_conf_org, $i + 1, 0, $merge_comment, $new_value);
126#					$match = 1;
127				}
128				$match = 1;
129			} else {
130				# is it really a definition or just a comment?
131				if (@new_conf_org[$i] =~ / = /) {
132					# commented in new config, add the old entry
133					mlog("add: $header line $i: @new_conf_org[$i] -> $new_value");
134					splice(@new_conf_org, $i + 1, 0, $merge_comment, $new_value);
135					$i++;$i++;
136					$match = 1;
137				}
138			}
139#			$match = 1 if $new_value eq @new_conf_org[$i];
140			$last_index = $i;
141			return if ($match eq 1);
142			$match = 0;
143		}	
144	}
145	return;
146}
147
148foreach (@old_conf) {
149	# check for section headers
150	if (/^\[/) {
151		# standard headers?
152		if (!/^\[global\]|^\[homes\]|^\[netlogon\]|^\[Profiles\]|^\[printers\]|^\[print\$\]|^\[pdf-generator\]/) {
153			# non-standard - add to new config
154			$user_parms = 1;
155			push (@new_conf, $_);
156		} else {
157			$user_parms = 0;
158			chop;
159			$header = $_;
160			s/\[|\]|\$//g;
161			$bare_header = $_;
162		}
163	} else {
164		# non-standard - add to new config
165		if ($user_parms == 1) {
166			push (@new_conf, $_);
167		} else {
168			# now we're working with standard settings
169			# update new config with values if they differ or are commented out
170			# translate any old nomenclature to the new style
171			# may still be some commented lines buried
172			# throw those out and try to merge into new config
173			if (!/^[ ]+#|^[ ]+;|^#|^;/) {
174#				print "$header: $_\n";
175				merge_conf($bare_header, $_);
176			}
177		}
178	}
179}
180
181# write the user config data to new smb.conf
182
183mlog("\nNew data for smb.conf:\n\n");
184mlog("@new_conf");
185
186if ($ARGV[0] eq "commit" || $ARGV[0] eq "test-commit") {
187	local *NEWCONF;
188	open(NEWCONF, "> $merged_conf_file");
189	print NEWCONF @new_conf_org;
190	print NEWCONF @new_conf;
191	close NEWCONF;
192	local *LOGFILE;
193	open(LOGFILE, "> $log_file");
194	print LOGFILE @merge_log;
195	close LOGFILE
196}
197
198