Project

General

Profile

Download (38.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	installer.php (pfSense installer)
4
	part of pfSense (http://www.pfsense.com/)
5
	Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com>
6
	All rights reserved.
7

    
8
	Redistribution and use in source and binary forms, with or without
9
	modification, are permitted provided that the following conditions are met:
10

    
11
	1. Redistributions of source code must retain the above copyright notice,
12
	   this list of conditions and the following disclaimer.
13

    
14
	2. Redistributions in binary form must reproduce the above copyright
15
	   notice, this list of conditions and the following disclaimer in the
16
	   documentation and/or other materials provided with the distribution.
17

    
18
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
	POSSIBILITY OF SUCH DAMAGE.
28
*/
29

    
30
$nocsrf = true;
31

    
32
require("globals.inc");
33
require("guiconfig.inc");
34

    
35
define('PC_SYSINSTALL', '/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh');
36

    
37
if($g['platform'] == "pfSense" or $g['platform'] == "nanobsd") {
38
	Header("Location: /");
39
	exit;
40
}
41

    
42
// Main switch dispatcher
43
switch ($_REQUEST['state']) {
44
	case "update_installer_status":
45
		update_installer_status();
46
		exit;
47
	case "custominstall":
48
		installer_custom();
49
		exit;
50
	case "begin_install":
51
		installing_gui();
52
		begin_install();
53
		exit;
54
	case "verify_before_install":
55
		verify_before_install();
56
		exit;
57
	case "easy_install_ufs":
58
		easy_install("UFS+S");
59
		exit;
60
	case "easy_install_ufs":
61
		easy_install("ZFS");
62
		exit;
63

    
64
	default:
65
		installer_main();	
66
}
67

    
68
function easy_install($fstype = "UFS+S") {
69
	// Calculate swap and disk sizes
70
	$disks = installer_find_all_disks();
71
	$memory = get_memory();
72
	$swap_size = $memory[0] * 2;
73
	$first_disk = trim(installer_find_first_disk());
74
	$disk_info = pcsysinstall_get_disk_info($first_disk);
75
	$size = $disk_info['size'];
76
	$first_disk_size = $size - $swap_size;
77
	$disk_setup = array();
78
	$tmp_array = array();
79
	// Build the disk layout for /
80
	$tmp_array['disk'] = $first_disk;
81
	$tmp_array['size'] = $first_disk_size;
82
	$tmp_array['mountpoint'] = "/";
83
	$tmp_array['fstype'] = $fstype;
84
	$disk_setup[] = $tmp_array;
85
	// Build the disk layout for SWAP
86
	$tmp_array['disk'] = $first_disk;
87
	$tmp_array['size'] = $swap_size;
88
	$tmp_array['mountpoint'] = "none";
89
	$tmp_array['fstype'] = "SWAP";
90
	$disk_setup[] = $tmp_array;
91
	unset($tmp_array);
92
	$bootmanager = "bsd";
93
	file_put_contents("/tmp/webInstaller_disk_layout.txt", serialize($disk_setup));
94
	file_put_contents("/tmp/webInstaller_disk_bootmanager.txt", serialize($bootmanager));
95
	Header("Location: installer.php?state=verify_before_install");
96
	exit;
97
}
98

    
99
function write_out_pc_sysinstaller_config($disks, $bootmanager = "bsd") {
100
	$diskareas = "";
101
	$fd = fopen("/usr/sbin/pc-sysinstall/examples/pfSense-install.cfg", "w");
102
	if(!$fd) {
103
		return true;
104
	}
105
	if($bootmanager == "") 
106
	 	$bootmanager = "none";
107
	$numdisks = -1;
108
	$lastdisk = "";
109
	$diskdefs = "";
110
	// Run through the disks and create the conf areas for pc-sysinstaller
111
	foreach($disks as $disksa) {
112
		$fstype = $disksa['fstype'];
113
		$size = $disksa['size'];
114
		$mountpoint = $disksa['mountpoint'];
115
		$disk = $disksa['disk'];
116
		if($disk <> $lastdisk) {
117
			$lastdisk = $disk;
118
			$numdisks++;
119
			$diskdefs .= "# disk {$disk}\n";
120
			$diskdefs .= "disk{$numdisks}={$disk}\n";
121
			$diskdefs .= "partition=all\n";
122
			$diskdefs .= "bootManager={$bootmanager}\n";
123
			$diskdefs .= "commitDiskPart\n\n";
124
		}
125
		$diskareas .= "disk{$numdisks}-part={$fstype} {$size} {$mountpoint} \n";
126
		if($encpass)
127
			$diskareas .= "encpass={$encpass}\n";
128
	}
129
	
130
	$config = <<<EOF
131
# Sample configuration file for an installation using pc-sysinstall
132
# This file was automatically generated by installer.php
133
 
134
installMode=fresh
135
installInteractive=yes
136
installType=FreeBSD
137
installMedium=LiveCD
138

    
139
# Set the disk parameters
140
{$diskdefs}
141

    
142
# Setup the disk label
143
# All sizes are expressed in MB
144
# Avail FS Types, UFS, UFS+S, UFS+J, ZFS, SWAP
145
# Size 0 means use the rest of the slice size
146
# Alternatively, you can append .eli to any of
147
# the above filesystem types to encrypt that disk.
148
# If you with to use a passphrase with this 
149
# encrypted partition, on the next line 
150
# the flag "encpass=" should be entered:
151
# encpass=mypass
152
# disk0-part=UFS 500 /boot
153
# disk0-part=UFS.eli 500 /
154
# disk0-part=UFS.eli 500 /usr
155
{$diskareas}
156

    
157
# Do it now!
158
commitDiskLabel
159

    
160
# Set if we are installing via optical, USB, or FTP
161
installType=FreeBSD
162

    
163
packageType=cpdup
164

    
165
# Optional Components
166
cpdupPaths=boot,COPYRIGHT,bin,conf,conf.default,dev,etc,home,kernels,libexec,lib,root,sbin,usr,var
167

    
168
# runExtCommand=chmod a+rx /usr/local/bin/after_installation_routines.sh ; cd / ; /usr/local/bin/after_installation_routines.sh
169
EOF;
170
	fwrite($fd, $config);
171
	fclose($fd);
172
	return;
173
}
174

    
175
function start_installation() {
176
	global $g, $fstype, $savemsg;
177
	if(file_exists("/tmp/install_complete"))
178
		return;
179
	$ps_running = exec("/bin/ps awwwux | /usr/bin/grep -v grep | /usr/bin/grep 'sh /tmp/installer.sh'");
180
	if($ps_running)	
181
		return;
182
	$fd = fopen("/tmp/installer.sh", "w");
183
	if(!$fd) {
184
		die(gettext("Could not open /tmp/installer.sh for writing"));
185
		exit;
186
	}
187
	fwrite($fd, "/bin/rm /tmp/.pc-sysinstall/pc-sysinstall.log 2>/dev/null\n");
188
	fwrite($fd, "/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh -c /usr/sbin/pc-sysinstall/examples/pfSense-install.cfg \n");
189
	fwrite($fd, "/bin/chmod a+rx /usr/local/bin/after_installation_routines.sh\n");
190
	fwrite($fd, "cd / && /usr/local/bin/after_installation_routines.sh\n");
191
	fwrite($fd, "/bin/mkdir /mnt/tmp\n");
192
	fwrite($fd, "/usr/bin/touch /tmp/install_complete\n");
193
	fclose($fd);
194
	exec("/bin/chmod a+rx /tmp/installer.sh");
195
	mwexec_bg("/bin/sh /tmp/installer.sh");
196
}
197

    
198
function installer_find_first_disk() {
199
	global $g, $fstype, $savemsg;
200
	$disk = `/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh disk-list | head -n1 | cut -d':' -f1`;
201
	return trim($disk);
202
}
203

    
204
function pcsysinstall_get_disk_info($diskname) {
205
	global $g, $fstype, $savemsg;
206
	$disk = split("\n", `/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh disk-list`);
207
	$disks_array = array();
208
	foreach($disk as $d) {
209
		$disks_info = split(":", $d);
210
		$tmp_array = array();
211
		if($disks_info[0] == $diskname) {
212
			$disk_info = split("\n", `/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh disk-info {$disks_info[0]}`);
213
			$disk_info_split = split("=", $disk_info);
214
			foreach($disk_info as $di) { 
215
				$di_s = split("=", $di);
216
				if($di_s[0])
217
					$tmp_array[$di_s[0]] = $di_s[1];
218
			}
219
			$tmp_array['size']--;
220
			$tmp_array['disk'] = trim($disks_info[0]);
221
			$tmp_array['desc'] = trim(htmlentities($disks_info[1]));
222
			return $tmp_array;
223
		}
224
	}
225
}
226

    
227
// Return an array with all disks information.
228
function installer_find_all_disks() {
229
	global $g, $fstype, $savemsg;
230
	$disk = split("\n", `/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh disk-list`);
231
	$disks_array = array();
232
	foreach($disk as $d) {
233
		if(!$d) 
234
			continue;
235
		$disks_info = split(":", $d);
236
		$tmp_array = array();
237
		$disk_info = split("\n", `/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh disk-info {$disks_info[0]}`);
238
		foreach($disk_info as $di) { 
239
			$di_s = split("=", $di);
240
			if($di_s[0])
241
				$tmp_array[$di_s[0]] = $di_s[1];
242
		}
243
		$tmp_array['size']--;
244
		$tmp_array['disk'] = trim($disks_info[0]);
245
		$tmp_array['desc'] = trim(htmlentities($disks_info[1]));
246
		$disks_array[] = $tmp_array;
247
	}
248
	return $disks_array;
249
}
250

    
251
function update_installer_status() {
252
	global $g, $fstype, $savemsg;
253
	// Ensure status files exist
254
	if(!file_exists("/tmp/installer_installer_running"))
255
		touch("/tmp/installer_installer_running");
256
	$status = `cat /tmp/.pc-sysinstall/pc-sysinstall.log`;
257
	$status = str_replace("\n", "\\n", $status);
258
	$status = str_replace("\n", "\\r", $status);
259
	echo "this.document.forms[0].installeroutput.value='$status';\n";
260
	echo "this.document.forms[0].installeroutput.scrollTop = this.document.forms[0].installeroutput.scrollHeight;\n";	
261
	// Find out installer progress
262
	$progress = "5";
263
	if(strstr($status, "Running: dd")) 
264
		$progress = "6";
265
	if(strstr($status, "Running: gpart create -s GPT")) 
266
		$progress = "7";
267
	if(strstr($status, "Running: gpart bootcode")) 
268
		$progress = "7";
269
	if(strstr($status, "Running: newfs -U")) 
270
		$progress = "8";
271
	if(strstr($status, "Running: sync")) 
272
		$progress = "9";
273
	if(strstr($status, "/boot /mnt/boot")) 
274
		$progress = "10";
275
	if(strstr($status, "/COPYRIGHT /mnt/COPYRIGHT"))
276
		$progress = "11";
277
	if(strstr($status, "/bin /mnt/bin"))
278
		$progress = "12";
279
	if(strstr($status, "/conf /mnt/conf"))
280
		$progress = "15";
281
	if(strstr($status, "/conf.default /mnt/conf.default"))
282
		$progress = "20";
283
	if(strstr($status, "/dev /mnt/dev"))
284
		$progress = "25";
285
	if(strstr($status, "/etc /mnt/etc"))
286
		$progress = "30";
287
	if(strstr($status, "/home /mnt/home"))
288
		$progress = "35";
289
	if(strstr($status, "/kernels /mnt/kernels"))
290
		$progress = "40";
291
	if(strstr($status, "/libexec /mnt/libexec"))
292
		$progress = "50";
293
	if(strstr($status, "/lib /mnt/lib"))
294
		$progress = "60";
295
	if(strstr($status, "/root /mnt/root"))
296
		$progress = "70";
297
	if(strstr($status, "/sbin /mnt/sbin"))
298
		$progress = "75";
299
	if(strstr($status, "/sys /mnt/sys"))
300
		$progress = "80";
301
	if(strstr($status, "/usr /mnt/usr"))
302
		$progress = "95";
303
	if(strstr($status, "/usr /mnt/usr"))
304
		$progress = "90";
305
	if(strstr($status, "/var /mnt/var"))
306
		$progress = "95";
307
	if(strstr($status, "cap_mkdb /etc/login.conf"))
308
		$progress = "96";
309
	if(strstr($status, "Setting hostname"))
310
		$progress = "97";
311
	if(strstr($status, "umount -f /mnt"))
312
		$progress = "98";
313
	if(strstr($status, "umount -f /mnt"))
314
		$progress = "99";
315
	if(strstr($status, "Installation finished"))
316
		$progress = "100";
317
	// Check for error and bail if we see one.
318
	if(stristr($status, "error")) {
319
		$error = true;
320
		echo "\$('installerrunning').innerHTML='<img class=\"infoboxnpimg\" src=\"/themes/{$g['theme']}/images/icons/icon_exclam.gif\"> <font size=\"2\"><b>An error occurred.  Aborting installation.  <a href=\"/installer\">Back</a> to webInstaller'; ";
321
		echo "\$('progressbar').style.width='100%';\n";
322
		unlink_if_exists("/tmp/install_complete");
323
		return;
324
	}
325
	$running_old = trim(file_get_contents("/tmp/installer_installer_running"));
326
	if($installer_running <> "running") {
327
		$ps_running = exec("/bin/ps awwwux | /usr/bin/grep -v grep | /usr/bin/grep 'sh /tmp/installer.sh'");
328
		if($ps_running)	{
329
			$running = "\$('installerrunning').innerHTML='<table><tr><td valign=\"middle\"><img src=\"/themes/{$g['theme']}/images/misc/loader.gif\"></td><td valign=\"middle\">&nbsp;<font size=\"2\"><b>Installer running ({$progress}% completed)...</td></tr></table>'; ";
330
			if($running_old <> $running) {
331
				echo $running;
332
				file_put_contents("/tmp/installer_installer_running", "$running");			
333
			}
334
		}
335
	}
336
	if($progress) 
337
		echo "\$('progressbar').style.width='{$progress}%';\n";
338
	if(file_exists("/tmp/install_complete")) {
339
		echo "\$('installerrunning').innerHTML='<img class=\"infoboxnpimg\" src=\"/themes/{$g['theme']}/images/icons/icon_exclam.gif\"> <font size=\"+1\">Installation completed.  Please <a href=\"/reboot.php\">reboot</a> to continue';\n";
340
		echo "\$('pbdiv').Fade();\n";
341
		unlink_if_exists("/tmp/installer.sh");
342
		file_put_contents("/tmp/installer_installer_running", "finished");
343
	}
344
}
345

    
346
function update_installer_status_win($status) {
347
	global $g, $fstype, $savemsg;
348
	echo "<script type=\"text/javascript\">\n";
349
	echo "	\$('installeroutput').value = '" . str_replace(htmlentities($status), "\n", "") . "';\n";
350
	echo "</script>";
351
}
352

    
353
function begin_install() {
354
	global $g, $savemsg;
355
	if(file_exists("/tmp/install_complete"))
356
		return;
357
	unlink_if_exists("/tmp/install_complete");
358
	update_installer_status_win(sprintf(gettext("Beginning installation on disk %s."),$disk));
359
	start_installation();
360
}
361

    
362
function head_html() {
363
	global $g, $fstype, $savemsg;
364
	echo <<<EOF
365
<html>
366
	<head>
367
		<style type='text/css'>
368
			hr {
369
				border: 0;
370
				color: #000000;
371
				background-color: #000000;
372
				height: 1px;
373
				width: 100%;
374
				text-align: left;
375
			}
376
			a:link { 
377
				color: #000000;
378
				text-decoration:underline;
379
				font-size:14;
380
			}
381
			a:visited { 
382
				color: #000000;
383
				text-decoration:underline;
384
				font-size:14;
385
			}
386
			a:hover { 
387
				color: #FFFF00;
388
				text-decoration: none;
389
				font-size:14;
390
			}
391
			a:active { 
392
				color: #FFFF00;
393
				text-decoration:underline;
394
				font-size:14;
395
			}
396
		</style>
397
	</head>
398
EOF;
399

    
400
}
401

    
402
function body_html() {
403
	global $g, $fstype, $savemsg;
404
	$pfSversion = str_replace("\n", "", file_get_contents("/etc/version"));
405
	if(strstr($pfSversion, "1.2")) 
406
		$one_two = true;
407
	$pgtitle = array("{$g['product_name']}", gettext("Installer"));
408
	include("head.inc");
409
	echo <<<EOF
410
	<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
411
	<script src="/javascript/scriptaculous/prototype.js" type="text/javascript"></script>
412
	<script src="/javascript/scriptaculous/scriptaculous.js" type="text/javascript"></script>
413
	<script type="text/javascript">
414
		function getinstallerprogress() {
415
			url = '/installer/installer.php';
416
			pars = 'state=update_installer_status';
417
			callajax(url, pars, installcallback);
418
		}
419
		function callajax(url, pars, activitycallback) {
420
			var myAjax = new Ajax.Request(
421
				url,
422
				{
423
					method: 'post',
424
					parameters: pars,
425
					onComplete: activitycallback
426
				});
427
		}
428
		function installcallback(transport) {
429
			setTimeout('getinstallerprogress()', 2000);
430
			eval(transport.responseText);
431
		}
432
	</script>
433
EOF;
434

    
435
	if($one_two)
436
		echo "<p class=\"pgtitle\">{$pgtitle}</font></p>";
437

    
438
	if ($savemsg) print_info_box($savemsg); 
439
}
440

    
441
function end_html() {
442
	global $g, $fstype, $savemsg;
443
	echo "</form>";
444
	echo "</body>";
445
	echo "</html>";
446
}
447

    
448
function template() {
449
	global $g, $fstype, $savemsg;
450
	head_html();
451
	body_html();
452
	echo <<<EOF
453
	<div id="mainlevel">
454
		<table width="100%" border="0" cellpadding="0" cellspacing="0">
455
	 		<tr>
456
	    		<td>
457
					<div id="mainarea">
458
						<table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
459
							<tr>
460
	     						<td class="tabcont" >
461
	      							<form action="installer.php" method="post">
462
									<div id="pfsensetemplate">
463

    
464

    
465
									</div>
466
	     						</td>
467
							</tr>
468
						</table>
469
					</div>
470
				</td>
471
			</tr>
472
		</table>
473
	</div>
474
EOF;
475
	end_html();
476
}
477

    
478
function verify_before_install() {
479
	global $g, $fstype, $savemsg;
480
	$encrypted_root = false;
481
	$non_encrypted_boot = false;
482
	$non_encrypted_notice = false;
483
	head_html();
484
	body_html();
485
	page_table_start($g['product_name'] . " installer - Verify final installation settings");
486
	// If we are visiting this step from anything but the row editor / custom install
487
	// then load the on disk layout contents if they are available.
488
	if(!$_REQUEST['fstype0'] && file_exists("/tmp/webInstaller_disk_layout.txt")) {
489
		$disks = unserialize(file_get_contents("/tmp/webInstaller_disk_layout.txt"));
490
		$bootmanager = unserialize(file_get_contents("/tmp/webInstaller_disk_bootmanager.txt"));
491
		$restored_layout_from_file = true;
492
		$restored_layout_txt = "The previous disk layout was restored from disk";
493
	} else {
494
		$disks = array();
495
	}
496
	if(!$bootmanager) 
497
		$bootmanager = $_REQUEST['bootmanager'];
498
	echo "\n<!--" . print_r($_REQUEST, true) . " -->\n";
499
	$disk = pcsysinstall_get_disk_info(htmlspecialchars($_REQUEST['disk']));
500
	$disksize = format_bytes($disk['size'] * 1048576);
501
	// Loop through posted items and create an array
502
	for($x=0; $x<99; $x++) { // XXX: Make this more optimal
503
		if(!$_REQUEST['fstype' . $x])
504
			continue;
505
		$tmparray = array();
506
		if($_REQUEST['fstype' . $x] <> "SWAP") {
507
			$tmparray['mountpoint'] = $_REQUEST['mountpoint' . $x];
508
			// Check for encrypted slice /
509
			if(stristr($_REQUEST['fstype' . $x], ".eli")) {
510
				if($tmparray['mountpoint'] == "/") 
511
					$encrypted_root = true;
512
			}
513
			// Check if we have a non-encrypted /boot
514
			if($tmparray['mountpoint'] == "/boot") 	{
515
				if(!stristr($_REQUEST['fstype' . $x], ".eli"))
516
					$non_encrypted_boot = true;
517
			}
518
			if($tmparray['mountpoint'] == "/conf") {	
519
				$tmparray['mountpoint'] = "/conf{$x}";
520
				$error_txt[] = "/conf is not an allowed mount point and has been renamed to /conf{$x}.";
521
			}
522
		} else  {
523
			$tmparray['mountpoint'] = "none";
524
		}
525
		// If we have an encrypted /root and lack a non encrypted /boot, throw an error/warning
526
		if($encrypted_root && !$non_encrypted_boot && !$non_encrypted_notice) {
527
			$error_txt[] = "A non-encrypted /boot slice is required when encrypting the / slice";
528
			$non_encrypted_notice = true;
529
		}
530
		$tmparray['disk'] = $_REQUEST['disk' . $x];
531
		$tmparray['fstype'] = $_REQUEST['fstype' . $x];
532
		$tmparray['size'] = $_REQUEST['size' . $x];
533
		$tmparray['encpass'] = $_REQUEST['encpass' . $x];
534
		$disks[] = $tmparray;
535
	}
536
	echo "\n<!-- " . print_r($disks, true) . " --> \n";
537
	$bootmanagerupper = strtoupper($bootmanager);
538
	echo <<<EOFAMBAC
539
	<form method="post" action="installer.php">
540
	<input type="hidden" name="fstype" value="{$fstype_echo}">
541
	<input type="hidden" name="disk" value="{$disk_echo}">
542
	<input type="hidden" name="state" value="begin_install">
543
	<input type="hidden" name="swapsize" value="{$swapsize}">
544
	<input type="hidden" name="encpass" value="{$encpass}">
545
	<input type="hidden" name="bootmanager" value="{$bootmanager}">
546
	<div id="mainlevel">
547
		<table width="800" border="0" cellpadding="0" cellspacing="0">
548
	 		<tr>
549
	    		<td>
550
					<div id="mainarea">
551
						<table width="100%" border="0" cellpadding="0" cellspacing="0">
552
							<tr>
553
	     						<td >
554
									<div>
555
										<center>
556
											<div id="pfsensetemplate">
557
												<table width='100%'>
558
EOFAMBAC;
559
												// If errors are found, throw the big red box.
560
												if ($error_txt) {
561
													echo "<tr><td colspan=\"5\">&nbsp;</td>";
562
													echo "<tr><td colspan=\"5\">";
563
													print_input_errors($error_txt);
564
													echo "</td></tr>";
565
												} else 
566
													echo "<tr><td>&nbsp;</td></tr>";
567

    
568
	echo <<<EOFAMBACBAF
569

    
570
												<tr><td colspan='5' align="center"><b>Boot manager: {$bootmanagerupper}</td></tr>
571
												<tr><td>&nbsp;</td></tr>
572
												<tr>
573
													<td align='left'>
574
														<b>Mount point</b>
575
													</td>
576
													<td align='left'>
577
														<b>Filesysytem type</b>
578
													</td>
579
													<td align='left'>
580
														<b>Disk</b>
581
													</td>
582
													<td align='left'>
583
														<b>Size</b>
584
													</td>
585
													<td align='left'>
586
														<b>Encryption password</b>
587
													</td>
588
												</tr>
589
												<tr><td colspan='5'><hr></td></tr>
590

    
591
EOFAMBACBAF;
592

    
593
													foreach($disks as $disk) {
594
														$desc = pcsysinstall_get_disk_info($disk['disk']);
595
														echo "<tr>";
596
														echo "<td>&nbsp;&nbsp;&nbsp;{$disk['mountpoint']}</td>";
597
														echo "<td>{$disk['fstype']}</td>";
598
														echo "<td>{$disk['disk']} {$desc['desc']}</td>";
599
														echo "<td>{$disk['size']}</td>";
600
														echo "<td>{$disk['encpass']}</td>";
601
														echo "</tr>";
602
													}
603

    
604
echo <<<EOFAMB
605
												<tr><td colspan="5"><hr></td></tr>
606
												</table>
607
											</div>
608
										</center>
609
									</div>
610
	     						</td>
611
							</tr>
612
						</table>
613
					</div>
614
					<center>
615
						<p/>
616
						<input type="button" value="Cancel" onClick="javascript:document.location='installer.php?state=custominstall';"> &nbsp;&nbsp;
617
EOFAMB;
618
						if(!$error_txt) 
619
						echo "<input type=\"submit\" value=\"Begin installation\"> <br/>&nbsp;";
620
echo <<<EOFAMBASDF
621

    
622
					</center>
623
				</td>
624
			</tr>
625
		</table>
626
	</div>
627
EOFAMBASDF;
628

    
629

    
630
	page_table_end();
631
	end_html();
632
	write_out_pc_sysinstaller_config($disks, $bootmanager);
633
	file_put_contents("/tmp/webInstaller_disk_layout.txt", serialize($disks));
634
	file_put_contents("/tmp/webInstaller_disk_bootmanager.txt", serialize($bootmanager));
635
}
636

    
637
function installing_gui() {
638
	global $g, $fstype, $savemsg;
639
	head_html();
640
	body_html();
641
	echo "<form action=\"installer.php\" method=\"post\" state=\"step1_post\">";
642
	page_table_start();
643
	echo <<<EOF
644
	<center>
645
		<table width="100%">
646
		<tr><td>
647
			<div id="mainlevel">
648
				<table width="100%" border="0" cellpadding="0" cellspacing="0">
649
			 		<tr>
650
			    		<td>
651
							<div id="mainarea">
652
								<table width="100%" border="0" cellpadding="0" cellspacing="0">
653
									<tr>
654
			     						<td>
655
											<div id="pfsenseinstaller" width="100%">
656
												<div id='installerrunning' width='100%' style="padding:8px; border:1px dashed #000000">
657
													<table>
658
														<tr>
659
															<td valign="middle">
660
																<img src="/themes/{$g['theme']}/images/misc/loader.gif">
661
															</td>
662
															<td valign="middle">
663
																&nbsp;<font size="2"><b>Starting Installer...  Please wait...
664
															</td>
665
														</tr>
666
													</table>
667
												</div>
668
												<div id='pbdiv'>
669
													<br/>
670
													<center>
671
													<table id='pbtable' height='15' width='640' border='0' colspacing='0' cellpadding='0' cellspacing='0'>
672
														<tr>
673
															<td background="/themes/the_wall/images/misc/bar_left.gif" height='15' width='5'>
674
															</td>
675
															<td>
676
																<table id="progholder" name="progholder" height='15' width='630' border='0' colspacing='0' cellpadding='0' cellspacing='0'>
677
																	<td background="/themes/the_wall/images/misc/bar_gray.gif" valign="top" align="left">
678
																		<img src='/themes/the_wall/images/misc/bar_blue.gif' width='0' height='15' name='progressbar' id='progressbar'>
679
																	</td>
680
																</table>
681
															</td>
682
															<td background="/themes/the_wall/images/misc/bar_right.gif" height='15' width='5'>
683
															</td>
684
														</tr>
685
													</table>
686
													<br/>
687
												</div>
688
												<textarea name='installeroutput' id='installeroutput' rows="31" cols="90">
689
												</textarea>
690
											</div>
691
			     						</td>
692
									</tr>
693
								</table>
694
							</div>
695
						</td>
696
					</tr>
697
				</table>
698
			</div>
699
		</td></tr>
700
		</table>
701
	</center>
702
	<script type="text/javascript">setTimeout('getinstallerprogress()', 250);</script>
703

    
704
EOF;
705
	page_table_end();
706
	end_html();
707
}
708

    
709
function page_table_start($pgtitle = "") {
710
	global $g, $fstype, $savemsg;
711
	if($pgtitle == "") 
712
		$pgtitle = "{$g['product_name']} installer";
713
	echo <<<EOF
714
	<center>
715
		<img border="0" src="/themes/{$g['theme']}/images/logo.gif"></a><br/>
716
		<table cellpadding="6" cellspacing="0" width="550" style="border:1px solid #000000">
717
		<tr height="10" bgcolor="#990000">
718
			<td style="border-bottom:1px solid #000000">
719
				<font color='white'>
720
					<b>
721
						{$pgtitle}
722
					</b>
723
				</font>
724
			</td>
725
		</tr>
726
		<tr>
727
			<td>
728

    
729
EOF;
730

    
731
}
732

    
733
function page_table_end() {
734
	global $g, $fstype, $savemsg;
735
	echo <<<EOF
736
			</td>
737
		</tr>
738
		</table>
739
	</center>
740

    
741
EOF;
742
	
743
}
744

    
745
function installer_custom() {
746
	global $g, $fstype, $savemsg;
747
	global $select_txt, $custom_disks;
748
	if(file_exists("/tmp/.pc-sysinstall/pc-sysinstall.log")) 
749
		unlink("/tmp/.pc-sysinstall/pc-sysinstall.log");
750
	$disks = installer_find_all_disks();
751
	// Pass size of disks down to javascript.
752
	$disk_sizes_js_txt = "var disk_sizes = new Array();\n";
753
	foreach($disks as $disk) 
754
		$disk_sizes_js_txt .= "disk_sizes['{$disk['disk']}'] = '{$disk['size']}';\n";
755
	head_html();
756
	body_html();
757
	page_table_start($g['product_name'] . " installer - Customize disk(s) layout");
758
	echo <<<EOF
759
		<script type="text/javascript">
760
			Array.prototype.in_array = function(p_val) {
761
				for(var i = 0, l = this.length; i < l; i++) {
762
					if(this[i] == p_val) {
763
						return true;
764
					}
765
				}
766
				return false;
767
			}
768
			function row_helper_dynamic_custom() {
769
				var totalsize = 0;
770
				{$disk_sizes_js_txt}
771
				// Run through all rows and process data
772
				for(var x = 0; x<99; x++) { //optimize me better
773
					if(\$('fstype' + x)) {
774
						if(\$('size' + x).value == '')
775
							\$('size' + x).value = disk_sizes[\$('disk' + x).value];
776
						var fstype = \$F('fstype' + x);
777
						if(fstype.substring(fstype.length - 4) == ".eli") {
778
							\$('encpass' + x).disabled = 0;
779
							if(!encryption_warning_shown) {
780
								alert('NOTE: If you define a disk encryption password you will need to enter it on *EVERY* bootup!');
781
								encryption_warning_shown = true;
782
							}
783
						} else { 
784
							\$('encpass' + x).disabled = 1;
785
						}
786
					}
787
					// Calculate size allocations
788
					if(\$('size' + x)) {
789
						if(parseInt($('size' + x).value) > 0)
790
							totalsize += parseInt($('size' + x).value);
791
					}
792
				}
793
				// If the totalsize element exists, set it and disable
794
				if(\$('totalsize')) {
795
					if(\$('totalsize').value != totalsize) {
796
						// When size allocation changes, draw attention.
797
 						new Effect.Highlight('totalsize');
798
						\$('totalsize').value = totalsize;
799
					}
800
					\$('totalsize').disabled = 1;
801
				}
802
				if(\$('disktotals')) {
803
					var disks_seen = new Array();
804
					var tmp_sizedisks = 0;
805
					var disksseen = 0;
806
					for(var xx = 0; xx<99; xx++) {
807
						if(\$('disk' + xx)) {
808
							if(!disks_seen.in_array(\$('disk' + xx).value)) {
809
								tmp_sizedisks += parseInt(disk_sizes[\$('disk' + xx).value]);
810
								disks_seen[disksseen] = \$('disk' + xx).value;
811
								disksseen++;
812
							}
813
						}
814
					\$('disktotals').value = tmp_sizedisks;
815
					\$('disktotals').disabled = 1;
816
					\$('disktotals').setStyle({color:'#000000'});
817
					var remaining = parseInt(\$('disktotals').value) - parseInt(\$('totalsize').value);
818
						if(remaining == 0) {
819
							if(\$('totalsize'))
820
								\$('totalsize').setStyle({
821
									background:'#00FF00',
822
									color:'#000000'
823
								});
824
						} else {
825
							if(\$('totalsize'))
826
								\$('totalsize').setStyle({
827
									background:'#FFFFFF',
828
									color:'#000000'
829
								});
830
						}
831
						if(parseInt(\$('totalsize').value) > parseInt(\$('disktotals').value)) {
832
							if(\$('totalsize'))
833
								\$('totalsize').setStyle({
834
									background:'#FF0000',
835
									color:'#000000'
836
								});							
837
						}
838
						if(\$('availalloc')) {
839
							\$('availalloc').disabled = 1;
840
							\$('availalloc').value = remaining;
841
								\$('availalloc').setStyle({
842
									background:'#FFFFFF',
843
									color:'#000000'
844
								});							
845
						}
846
					}
847
				}
848
			}
849
		</script>
850
		<script type="text/javascript" src="/javascript/row_helper_dynamic.js"></script>
851
		<script type="text/javascript">
852
			// Setup rowhelper data types
853
			rowname[0] = "mountpoint";
854
			rowtype[0] = "textbox";
855
			rowsize[0] = "8";
856
			rowname[1] = "fstype";
857
			rowtype[1] = "select";
858
			rowsize[1] = "1";
859
			rowname[2] = "disk";
860
			rowtype[2] = "select";
861
			rowsize[2] = "1";
862
			rowname[3] = "size";
863
			rowtype[3] = "textbox";
864
			rowsize[3] = "8";
865
			rowname[4] = "encpass";
866
			rowtype[4] = "textbox";
867
			rowsize[4] = "8";
868
			field_counter_js = 5;
869
			rows = 1;
870
			totalrows = 1;
871
			loaded = 1;
872
			rowhelper_onChange = 	" onChange='javascript:row_helper_dynamic_custom()' ";
873
			rowhelper_onDelete = 	"row_helper_dynamic_custom(); ";
874
			rowhelper_onAdd = 		"row_helper_dynamic_custom();";
875
		</script>
876
		<form action="installer.php" method="post">
877
			<input type="hidden" name="state" value="verify_before_install">
878
			<div id="mainlevel">
879
				<center>
880
				<table width="100%" border="0" cellpadding="5" cellspacing="0">
881
			 		<tr>
882
			    		<td>
883
							<center>
884
							<div id="mainarea">
885
								<center>
886
								<table width="100%" border="0" cellpadding="5" cellspacing="5">
887
									<tr>
888
			     						<td>
889
											<div id="pfsenseinstaller">
890
												<center>
891
												<div id='loadingdiv'>
892
													<table>
893
														<tr>
894
															<td valign="center">
895
																<img src="/themes/{$g['theme']}/images/misc/loader.gif">
896
															</td>
897
															<td valign="center">
898
														 		&nbsp;Probing disks, please wait...
899
															</td>
900
														</tr>
901
													</table>
902
												</div>
903
EOF;
904
	ob_flush();
905
	if(file_exists("/tmp/webInstaller_disk_bootmanager.txt"))
906
		$bootmanager = unserialize(file_get_contents("/tmp/webInstaller_disk_bootmanager.txt"));
907
	if($bootmanager == "none") 
908
		$noneselected = " SELECTED";
909
	if($bootmanager == "bsd") 
910
		$bsdeselected = " SELECTED";
911

    
912
	if(!$disks)  {
913
		$custom_txt = gettext("ERROR: Could not find any suitable disks for installation.");
914
	} else {
915
		// Prepare disk selection dropdown
916
		$custom_txt = <<<EOF
917
												<center>
918
												<table>
919
												<tr>
920
													<td align='right'>
921
														Boot manager:
922
													</td>
923
													<td>
924
														<select name='bootmanager'>
925
															<option value='none' $noneselected>
926
																None
927
															</option>
928
															<option value='bsd' $bsdeselected>
929
																BSD
930
															</option>
931
														</select>
932
													</td>
933
												</tr>
934
												</table>
935
												<hr>
936
												<table id='maintable'><tbody>
937
												<tr>
938
													<td align="middle">
939
														<b>Mount</b>
940
													</td>
941
													<td align='middle'>
942
														<b>Filesysytem</b>
943
													</td>
944
													<td align="middle">
945
														<b>Disk</b>
946
													</td>
947
													<td align="middle">
948
														<b>Size</b>
949
													</td>
950
													<td align="middle">
951
														<b>Encryption password</b>
952
													</td>
953
													<td>
954
														&nbsp;
955
													</td>
956
												</tr>
957
												<tr>
958

    
959
EOF;
960

    
961
		// Calculate swap disk sizes
962
		$memory = get_memory();
963
		$swap_size = $memory[0] * 2;
964
		$first_disk = trim(installer_find_first_disk());
965
		$disk_info = pcsysinstall_get_disk_info($first_disk);
966
		$size = $disk_info['size'];
967
		$first_disk_size = $size - $swap_size;
968

    
969
		// Debugging
970
		echo "\n\n<!-- $first_disk - " . print_r($disk_info, true) . " - $size  - $first_disk_size -->\n\n";
971

    
972
		// Check to see if a on disk layout exists
973
		if(file_exists("/tmp/webInstaller_disk_layout.txt")) {
974
			$disks_restored = unserialize(file_get_contents("/tmp/webInstaller_disk_layout.txt"));
975
			$restored_layout_from_file = true;
976
			$restored_layout_txt = "<br/>* The previous disk layout was restored from a previous session";
977
		}
978

    
979
		// If we restored disk layout(s) from a file then build the rows
980
		if($restored_layout_from_file == true) {
981
			$diskcounter = 0;
982
			foreach($disks_restored as $dr) {
983
				$custom_txt .= return_rowhelper_row("$diskcounter", $dr['mountpoint'], $dr['fstype'], $dr['disk'], $dr['size'], $dr['encpass']);
984
				$diskcounter++;
985
			}
986
		} else {		
987
			// Construct the default rows that outline the disks configuration.
988
			$custom_txt .= return_rowhelper_row("0", "/", "UFS+S", $first_disk, "{$first_disk_size}", "");
989
			$custom_txt .= return_rowhelper_row("1", "none", "SWAP", $first_disk, "$swap_size", "");
990
		}
991

    
992
		// tfoot and tbody are used by rowhelper
993
		$custom_txt .= "</tr>";
994
		$custom_txt .= "<tfoot></tfoot></tbody>";
995
		// Total allocation box
996
		$custom_txt .= "<tr><td></td><td></td><td align='right'>Total allocated:</td><td><input style='border:0px; background-color: #FFFFFF;' size='8' id='totalsize' name='totalsize'></td>";
997
		// Add row button
998
		$custom_txt .= "</td><td>&nbsp;</td><td>";
999
		$custom_txt .= "<div id=\"addrowbutton\">";
1000
		$custom_txt .= "<a onclick=\"javascript:addRowTo('maintable', 'formfldalias'); return false;\" href=\"#\">";
1001
		$custom_txt .= "<img border=\"0\" src=\"/themes/{$g['theme']}/images/icons/icon_plus.gif\" alt=\"\" title=\"add another entry\" /></a>";
1002
		$custom_txt .= "</div>";
1003
		$custom_txt .= "</td></tr>";	
1004
		// Disk capacity box
1005
		$custom_txt .= "<tr><td></td><td></td><td align='right'>Disk(s) capacity total:</td><td><input style='border:0px; background-color: #FFFFFF;' size='8' id='disktotals' name='disktotals'></td></tr>";
1006
		// Remaining allocation box
1007
		$custom_txt .= "<tr><td></td><td></td><td align='right'>Available space for allocation:</td><td><input style='border:0px; background-color: #FFFFFF;' size='8' id='availalloc' name='availalloc'></td></tr>";
1008
		$custom_txt .= "</table>";
1009
		$custom_txt .= "<script type=\"text/javascript\">row_helper_dynamic_custom();</script>";
1010
	}
1011
	echo <<<EOF
1012

    
1013
												<tr>
1014
													<td colspan='4'>
1015
													<script type="text/javascript">
1016
														\$('loadingdiv').style.visibility='hidden';
1017
													</script>
1018
													<div id='contentdiv' style="display:none;">
1019
														<p/>
1020
														{$custom_txt}<p/>
1021
														<hr><p/>
1022
														<input type="button" value="Cancel" onClick="javascript:document.location='/installer/installer.php';"> &nbsp;&nbsp
1023
														<input type="submit" value="Next">
1024
													</div>
1025
													<script type="text/javascript">
1026
														var encryption_warning_shown = false;
1027
														\$('contentdiv').appear();
1028
														row_helper_dynamic_custom();
1029
													</script>
1030
												</center>
1031
												</td></tr>
1032
												</table>
1033
											</div>
1034
			     						</td>
1035
									</tr>
1036
								</table>
1037
								</center>
1038
								<span class="vexpl">
1039
									<span class="red">
1040
										<strong>
1041
											NOTES:
1042
										</strong>
1043
									</span>
1044
									<br/>* Sizes are in megabytes.
1045
									<br/>* Mount points named /conf are not allowed.  Use /cf if you want to make a configuration slice/mount.
1046
									{$restored_layout_txt}
1047
								</span>
1048
								</strong>
1049
							</div>
1050
						</td>
1051
					</tr>
1052
				</table>
1053
			</div>
1054
			</center>
1055
			<script type="text/javascript">
1056
			<!--
1057
				newrow[1] = "{$select_txt}";
1058
				newrow[2] = "{$custom_disks}";
1059
			-->
1060
			</script>
1061
			
1062

    
1063
EOF;
1064
	page_table_end();
1065
	end_html();
1066
}
1067

    
1068
function installer_main() {
1069
	global $g, $fstype, $savemsg;
1070
	if(file_exists("/tmp/.pc-sysinstall/pc-sysinstall.log")) 
1071
		unlink("/tmp/.pc-sysinstall/pc-sysinstall.log");
1072
	head_html();
1073
	body_html();
1074
	$disk = installer_find_first_disk();
1075
	// Only enable ZFS if this exists.  The install will fail otherwise.
1076
	if(file_exists("/boot/gptzfsboot")) 
1077
		$zfs_enabled = "<tr bgcolor=\"#9A9A9A\"><td align=\"center\"><a href=\"installer.php?state=easy_install_zfs\">Easy installation of {$g['product_name']} using the ZFS filesystem on disk {$disk}</a></td></tr>";
1078
	page_table_start();
1079
	echo <<<EOF
1080
		<form action="installer.php" method="post" state="step1_post">
1081
			<div id="mainlevel">
1082
				<center>
1083
				<b><font face="arial" size="+2">Welcome to the {$g['product_name']} webInstaller!</b></font><p/>
1084
				<font face="arial" size="+1">This utility will install {$g['product_name']} to a hard disk, flash drive, etc.</font>
1085
				<table width="100%" border="0" cellpadding="5" cellspacing="0">
1086
			 		<tr>
1087
			    		<td>
1088
							<center>
1089
							<div id="mainarea">
1090
								<br/>
1091
								<center>
1092
								Please select an installer option to begin:
1093
								<p/>
1094
								<table width="100%" border="0" cellpadding="5" cellspacing="5">
1095
									<tr>
1096
			     						<td>
1097
											<div id="pfsenseinstaller">
1098
												<center>
1099
EOF;
1100
	if(!$disk) {
1101
		echo gettext("ERROR: Could not find any suitable disks for installation.");
1102
		echo "</div></td></tr></table></div></table></div>";
1103
		end_html();
1104
		exit;
1105
	}
1106
	echo <<<EOF
1107

    
1108
													<table cellspacing="5" cellpadding="5" style="border: 1px dashed;">
1109
														<tr bgcolor="#CECECE"><td align="center">
1110
															<a href="installer.php?state=easy_install_ufs">Easy installation of {$g['product_name']} using the UFS filesystem on disk {$disk}</a>
1111
														</td></tr>
1112
													 	{$zfs_enabled}
1113
														<tr bgcolor="#AAAAAA"><td align="center">
1114
															<a href="installer.php?state=custominstall">Custom installation of {$g['product_name']}</a>
1115
														</td></tr>
1116
														<tr bgcolor="#CECECE"><td align="center">
1117
															<a href='/'>Cancel and return to Dashboard</a>
1118
														</td></tr>
1119
													</table>
1120
												</center>
1121
											</div>
1122
			     						</td>
1123
									</tr>
1124
								</table>
1125
							</div>
1126
						</td>
1127
					</tr>
1128
				</table>
1129
			</div>
1130
EOF;
1131
	page_table_end();
1132
	end_html();
1133
}
1134

    
1135
function return_rowhelper_row($rownum, $mountpoint, $fstype, $disk, $size, $encpass) {
1136
		global $g, $select_txt, $custom_disks, $savemsg;
1137
		$release = php_uname("r");
1138
		$release = trim($release[0]);
1139

    
1140
		// Mount point
1141
		$disks = installer_find_all_disks();
1142
		$custom_txt .= "<tr>";
1143
		$custom_txt .=  "<td><input size='8' id='mountpoint{$rownum}' name='mountpoint{$rownum}' value='{$mountpoint}'></td>";
1144

    
1145
		// Filesystem type array
1146
		$types = array(
1147
			'UFS' => 'UFS',
1148
			'UFS+S' => 'UFS + Softupdates',
1149
			'UFS.eli' => 'Encrypted UFS',
1150
			'UFS+S.eli' => 'Encrypted UFS + Softupdates',
1151
			'SWAP' => 'SWAP'
1152
		);
1153

    
1154
		// UFS + Journaling was introduced in 9.0
1155
		if($release == "9") {
1156
			$types['UFS+J'] = "UFS + Journaling";
1157
			$types['UFS+J.eli'] = "Encrypted UFS + Journaling";
1158
		}
1159
		
1160
		// Add ZFS Boot loader if it exists
1161
		if(file_exists("/boot/gptzfsboot")) {
1162
			$types['ZFS'] = "Zetabyte Filesystem";
1163
			$types['ZFS.eli'] = "Encrypted Zetabyte Filesystem";
1164
		}
1165

    
1166
		// fstype form field
1167
		$custom_txt .=  "<td><select onChange='javascript:row_helper_dynamic_custom()' id='fstype{$rownum}' name='fstype{$rownum}'>";
1168
		$select_txt = "";
1169
		foreach($types as $type => $desc) {
1170
			if($type == $fstype)
1171
				$SELECTED="SELECTED";
1172
			else 
1173
				$SELECTED="";
1174
			$select_txt .= "<option value='$type' $SELECTED>$desc</option>";
1175
		}
1176
		$custom_txt .= "{$select_txt}</select>\n";
1177
		$custom_txt .= "</td>";
1178
		
1179
		// Disk selection form field
1180
		$custom_txt .= "<td><select id='disk{$rownum}' name='disk{$rownum}'>\n";
1181
		$custom_disks = "";
1182
		foreach($disks as $dsk) {
1183
			$disksize_bytes = format_bytes($dsk['size'] * 1048576);
1184
			$disksize = $dsk['size'];
1185
			if($disk == $dsk['disk'])
1186
				$SELECTED="SELECTED";
1187
			else 
1188
				$SELECTED="";
1189
			$custom_disks .= "<option value='{$dsk['disk']}' $SELECTED>{$dsk['disk']} - {$dsk['desc']} - {$disksize}MB ({$disksize_bytes})</option>";
1190
		}
1191
		$custom_txt .= "{$custom_disks}</select></td>\n";
1192

    
1193
		// Slice size
1194
		$custom_txt .= "<td><input onChange='javascript:row_helper_dynamic_custom();' name='size{$rownum}' id='size{$rownum}' size='8' type='text' value='{$size}'></td>";
1195

    
1196
		// Encryption password
1197
		$custom_txt .= "<td>";
1198
		$custom_txt .= "<input id='encpass{$rownum}' name='encpass{$rownum}' size='8' value='{$encpass}'>";
1199
		$custom_txt .= "</td>";
1200
	
1201
		// Add Rowhelper + button
1202
		if($rownum > 0) 
1203
			$custom_txt .= "<td><a onclick=\"removeRow(this); return false;\" href=\"#\"><img border=\"0\" src=\"/themes/{$g['theme']}/images/icons/icon_x.gif\" alt=\"\" title=\"remove this entry\"/></a></td>";
1204

    
1205
		$custom_txt .= "</tr>";	
1206
		return $custom_txt;
1207
}
1208

    
1209
?>
(2-2/2)