liblocsetup.pm 18.2 KB
Newer Older
1
2
3
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
Mike Hibler's avatar
Mike Hibler committed
4
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
5
6
7
8
# All rights reserved.
#

#
9
# CygWin specific routines and constants for the client bootime setup stuff.
10
11
12
13
14
#
package liblocsetup;
use Exporter;
@ISA = "Exporter";
@EXPORT =
15
    qw ( $CP $LN $RM $MV $TOUCH $EGREP $CHOWN $CHMOD $MOUNT $UMOUNT
Mike Hibler's avatar
Mike Hibler committed
16
	 $NTS $NET $HOSTSFILE
17
	 $TMPASSWD $SFSSD $SFSCD $RPMCMD
18
	 os_account_cleanup os_accounts_start os_accounts_end os_accounts_sync
19
20
	 os_ifconfig_line os_etchosts_line
	 os_setup os_groupadd os_groupgid os_useradd os_userdel os_usermod os_mkdir
21
22
23
	 os_ifconfig_veth
	 os_routing_enable_forward os_routing_enable_gated
	 os_routing_add_manual os_routing_del_manual os_homedirdel
24
25
	 os_groupdel os_samba_mount 
	 os_getnfsmounts os_getnfsmountpoints os_noisycmd
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
	 os_fwconfig_line os_fwrouteconfig_line
       );

# Must come after package declaration!
use English;

# Load up the paths. Its conditionalized to be compatabile with older images.
# Note this file has probably already been loaded by the caller.
BEGIN
{
    if (-e "/etc/emulab/paths.pm") {
	require "/etc/emulab/paths.pm";
	import emulabpaths;
    }
    else {
	my $ETCDIR  = "/etc/rc.d/testbed";
	my $BINDIR  = "/etc/rc.d/testbed";
	my $VARDIR  = "/etc/rc.d/testbed";
	my $BOOTDIR = "/etc/rc.d/testbed";
    }
}

48
49
use librc;

50
#
51
# Various programs and things specific to CygWin on XP and that we want to export.
52
# 
Mike Hibler's avatar
Mike Hibler committed
53
54
$CP		= "/bin/cp";
$LN		= "/bin/ln";
55
$RM		= "/bin/rm";
56
57
58
$MV		= "/bin/mv";
$TOUCH		= "/bin/touch";
$EGREP		= "/bin/egrep -q";
59
$CHOWN		= "/bin/chown";
Mike Hibler's avatar
Mike Hibler committed
60
$CHMOD		= "/bin/chmod";
61
$MOUNT		= "/bin/mount";
62
$UMOUNT		= "/bin/umount";
63

64
# Cygwin.
65
66
67
$MKPASSWD	= "/bin/mkpasswd";
$MKGROUP	= "/bin/mkgroup";
$AWK		= "/bin/gawk";
68
$BASH		= "/bin/bash";
69

70
# Windows under Cygwin.
71
72
$NTS		= "/cygdrive/c/WINDOWS/system32";
$NET		= "$NTS/net";
73
74
$NETSH		= "$NTS/netsh";
$NTE		= "$NTS/drivers/etc";
Mike Hibler's avatar
Mike Hibler committed
75

76
77
$HOSTSFILE	= "$NTE/hosts";
#$HOSTSFILE	= "/etc/hosts";
78

79
80
81
#
# These are not exported
#
82
83
my $ADDUSERS	= "$BINDIR/addusers.exe";
my $DEVCON	= "$BINDIR/devcon.exe";
84
my $IFCONFIGBIN = "$NETSH interface ip set address";
85
86
my $IFCONFIG	= "$IFCONFIGBIN name=\"%s\" source=static addr=%s mask=%s";
my $IFC_1000MBS = "1000baseTx";
87
88
89
90
91
92
my $IFC_100MBS  = "100baseTx";
my $IFC_10MBS   = "10baseT";
my $IFC_FDUPLEX = "FD";
my $IFC_HDUPLEX = "HD";
my @LOCKFILES   = ("/etc/group.lock", "/etc/gshadow.lock");
my $MKDIR	= "/bin/mkdir";
93
my $RMDIR	= "/bin/rmdir";
94
my $GATED	= "/usr/sbin/gated";
Mike Hibler's avatar
Mike Hibler committed
95
my $ROUTE	= "$NTS/route";
96
97
my $SHELLS	= "/etc/shells";
my $DEFSHELL	= "/bin/tcsh";
98
99
my $winusersfile = "$BOOTDIR/winusers";
my $usershellsfile = "$BOOTDIR/usershells";
100
my $XIMAP	= "$BOOTDIR/xif_map";
101

Russ Fish's avatar
Russ Fish committed
102
103
104
105
106
107
108
109
110
111
112
#
# system() with error checking.
#
sub mysystem($)
{
    my ($cmd) = @_;
    if (system($cmd) != 0) {
	warning("Failed: ($cmd), $!\n");
    }
}

113
114
115
116
#
# OS dependent part of cleanup node state.
# 
sub os_account_cleanup()
117
118
119
120
121
122
123
{
    # Undo what rc.mounts and rc.accounts did.  

    # The users list could be gotten from multiple places; let's use the /users
    # directory as truth.
    if (opendir(DIRHANDLE, "/users")) {
	while ($name = readdir(DIRHANDLE)) {
124
	    if ($name =~ m/^\.+/ || $name =~ m/^Administrator$/) {
125
126
127
128
129
		next;
	    }
	    print "Removing user: $name\n";

	    # There is always an NT account.
Russ Fish's avatar
Russ Fish committed
130
	    mysystem("$NET user $name /delete >& /dev/null");
131
132

	    # There will only be an NT homedir if the user has logged in sometime.
Russ Fish's avatar
Russ Fish committed
133
134
	    system("$CHMOD -Rf 777 C:/'Documents and Settings'/$name >& /dev/null");
	    system("$CHOWN -Rf root C:/'Documents and Settings'/$name >& /dev/null");
Russ Fish's avatar
Russ Fish committed
135
	    system("$RM -rf C:/'Documents and Settings'/$name ");
Russ Fish's avatar
Russ Fish committed
136
	    # It sometimes also makes user.PCnnn, user.PCnnn.000, etc.
Russ Fish's avatar
Russ Fish committed
137
138
	    system("$CHMOD -Rf 777 C:/'Documents and Settings'/$name.* >& /dev/null");
	    system("$CHOWN -Rf root C:/'Documents and Settings'/$name.* >& /dev/null");
139
	    system("$RM -rf C:/'Documents and Settings'/$name.*");
140
141

	    # Unmount the homedir so we can get to the mount point.
142
143
	    system("$UMOUNT /users/$name");
	    system("$RMDIR /users/$name");
144
145
146
147
148
149
150
	}
	closedir(DIRHANDLE);

	# Make the CygWin /etc/passwd and /etc/group files match Windows.
	os_accounts_sync();
    }

151
152
153
154
155
156
157
    # Clean out the user /sshkeys directories, leaving /sshkeys/root alone.
    if (opendir(DIRHANDLE, "/sshkeys")) {
	while ($name = readdir(DIRHANDLE)) {
	    if ($name =~ m/^\.+/ || $name =~ m/^root$/) {
		next;
	    }

158
159
160
	    # Open up an existing key dir to the root user.  Even though root
	    # is in the Administrators group, it's locked out by permissions.
	    mysystem("$CHMOD 777 /sshkeys/$name");
Russ Fish's avatar
Russ Fish committed
161
162
	    mysystem("$CHOWN -Rf root /sshkeys/$name");
	    mysystem("$RM -rf /sshkeys/$name");
163
164
	}
	closedir(DIRHANDLE);
165
166
    }

Russ Fish's avatar
Russ Fish committed
167
    # Clean out the /proj subdirectories.
168
169
170
171
172
173
174
175
    if (opendir(DIRHANDLE, "/proj")) {
	while ($name = readdir(DIRHANDLE)) {
	    if ($name =~ m/^\.+/) {
		next;
	    }
	    print "Removing project: $name\n";

	    # Unmount the project dir so we can get to the mount point.
Russ Fish's avatar
Russ Fish committed
176
177
	    mysystem("$UMOUNT /proj/$name");
	    mysystem("$RMDIR /proj/$name");
178
179
180
	}
    }

Russ Fish's avatar
Russ Fish committed
181
182
    # Just unmount /share, everybody gets one.
    mysystem("$UMOUNT /share");
183
184
185
186
187
188
}

# 
# Make the CygWin /etc/passwd and /etc/group files match Windows.
# 
sub os_accounts_sync()
189
190
191
192
{
    unlink @LOCKFILES;

    # Generate the CygWin password and group files from the registry users.
193
    # Note that the group membership is not reported into the CygWin files.
194
195
    print "Resetting the CygWin passwd and group files.\n";

196
197
    my $cmd = "$MKPASSWD -l | $AWK -F: '";
    $cmd   .=   'BEGIN{ OFS=":" } ';
198
    # Make root's UID zero.  Put non-root homedirs under /users, not /home.
199
200
201
202
203
    $cmd   .=   '{ if ($1=="root") $3="0"; else sub("/home/", "/users/"); print }'; 
    $cmd   .= "'";
    # Apply the users' shell preferences.
    $cmd   .= " | sed -f $usershellsfile"
	if (-e $usershellsfile);
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    $cmd   .= " > /etc/passwd.new";
    ##print "$cmd\n";
    if (system("$cmd") != 0) {
	warning("Could not generate /etc/password.new file: $!\n");
	return -1;
    }

    # Work around "/etc/passwd: Device or resource busy".
    $cmd    = "$MV /etc/passwd /etc/passwd.prev";
    ##print "$cmd\n";
    if (system("$cmd") != 0) {
	warning("Could not $cmd $!\n");
	return -1;
    }
    $cmd    = "$MV /etc/passwd.new /etc/passwd";
219
220
    ##print "$cmd\n";
    if (system("$cmd") != 0) {
221
	warning("Could not $cmd $!\n");
222
223
	return -1;
    }
224

225
    $cmd  = "$MKGROUP -l | $AWK '";
226
227
228
229
230
    # Make a duplicate group line that is a wheel alias for Administrators.
    $cmd .= '/^Administrators:/{print "wheel" substr($0, index($0,":"))} {print}';
    $cmd .= "' > /etc/group";
    ##print "$cmd\n";
    if (system("$cmd") != 0) {
231
	warning("Could not generate /etc/group file: $!\n");
232
233
234
235
236
237
238
239
240
241
	return -1;
    }
    
    return 0;
}

#
# Generate and return an ifconfig line that is approriate for putting
# into a shell script (invoked at bootup).
#
242
my %dev_map = ();
243
244
245
246
247
248
sub os_ifconfig_line($$$$$$$;$$)
{
    my ($iface, $inet, $mask, $speed, $duplex, $aliases,
	$iface_type, $settings, $rtabid) = @_;
    my ($uplines, $downlines);

249
250
251
252
253
254
    if (! $dev_map) {
	# Map from non-control interface names, e.g. "Local Area Connection #4"
	# to the Device Instance ID's used as devcon arguments, e.g.
	# "@PCI\VEN_8086&DEV_1010&SUBSYS_10128086&REV_01\5&2FA58B96&0&210030".
	if (! open(DEVMAP, $XIMAP)) {
	    warning("Cannot open $XIMAP $!\n");
Russ Fish's avatar
Tweaks.    
Russ Fish committed
255
	}
256
257
258
259
260
261
262
263
264
265
	else {
	    while (my $dev_line = <DEVMAP>) {
		chomp($dev_line);
		my ($dev_name, $dev_inst) = split(":", $dev_line, 2);
		$dev_map{$dev_name} = $dev_inst;
	    }
	    close(DEVMAP);
	}
    }

266
267
    if ($inet ne "") {
	$uplines  .= sprintf($IFCONFIG, $iface, $inet, $mask);
268
269
	$uplines  .= sprintf("\n    echo \"Enabling %s on %s\"", $iface, $inet);
	$uplines  .= sprintf("\n    $DEVCON enable '%s'" , $dev_map{$iface});
Russ Fish's avatar
Russ Fish committed
270

271
272
	$downlines  .= sprintf("echo \"Disabling %s from %s\"", $iface, $inet);
	$downlines  .= sprintf("\n    $DEVCON disable '%s'" , $dev_map{$iface});
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    }
    
    return ($uplines, $downlines);
}

#
# Specialized function for configing locally hacked veth devices.
#
sub os_ifconfig_veth($$$$$;$$$)
{
    return "";
}

#
# Generate and return an string that is approriate for putting
# into /etc/hosts.
#
sub os_etchosts_line($$$)
{
    my ($name, $ip, $aliases) = @_;
    
294
295
    # Note: space rather than tab after the host name on Windows.
    return sprintf("%s %s %s", $ip, $name, $aliases);
296
297
}

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#
# On Windows NT, accumulate an input file for the addusers command.
# See "AddUsers Automates Creation of a Large Number of Users",
# http://support.microsoft.com/default.aspx?scid=kb;en-us;199878
# 
# The file format is comma-delimited, as follows:
# 
# [Users]
# User Name,Full name,Password,Description,HomeDrive,Homepath,Profile,Script
# 
# [Global] or [Local]
# Group Name,Comment,UserName,...
# 
my @groupNames;
my %groupsByGid;
my %groupMembers;
sub os_accounts_start()
{
    # Remember group info to be put out at the end.
    @groupNames = ();
    %groupsByGid = ();
    %groupMembers = ();

    if (! open(WINUSERS, "> $winusersfile")) {
322
323
324
325
	warning("os_accounts_start: Cannot create $winusersfile .\n");
	return -1;
    }

326
327
328
    # Don't wipe out previous user shell preferences, just add new ones.
    if (! open(USERSHELLS, ">> $usershellsfile")) {
	warning("os_accounts_start: Cannot create or append to $usershellsfile .\n");
329
330
331
332
	return -1;
    }

    # Users come before groups in the addusers.exe account stream.
333
    # Notice the <CR><LF>'s!  It's a Windows file.
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
    print WINUSERS "[Users]\r\n";

    return 0;
}

#
# Remember the mapping from an existing group GID to its name.
#
sub os_groupgid($$)
{
    my($group, $gid) = @_;

    $groupsByGid{$gid} = $group;    # Remember the name associated with the gid.

    return 0;
}

351
352
353
354
355
356
357
#
# Add a new group
# 
sub os_groupadd($$)
{
    my($group, $gid) = @_;

358
359
360
361
    push(@groupNames, $group);      # Remember all of the group names.
    os_groupgid($group, $gid);

    return 0;
362
363
364
365
366
367
368
369
370
}

#
# Delete an old group
# 
sub os_groupdel($)
{
    my($group) = @_;

371
372
    # Unimplemented.
    return -1;
373
374
375
376
377
378
379
380
381
}

#
# Remove a user account.
# 
sub os_userdel($)
{
    my($login) = @_;

382
383
    # Unimplemented.
    return -1;
384
385
386
}

#
387
388
# Modify user group membership and password.
# Changing the login shell is unimplemented.
389
390
391
392
393
# 
sub os_usermod($$$$$$)
{
    my($login, $gid, $glist, $pswd, $root, $shell) = @_;

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
    if ($root) {
	$glist .= ",0";
    }
    if ($glist ne "") {
	##print "glist '$glist'\n";
	my $gname;
	foreach my $grp (split(/,/, $glist)) {
	    if ( $grp eq "0" ) {
		$gname = "Administrators";
	    }
	    else {
		$gname = $groupsByGid{$grp};
	    }
	    ##print "login $login, grp $grp, gname '$gname'\n";
	    my $cmd = "$NET localgroup $gname | tr -d '\\r' | grep -q '^$login\$'";
	    ##print "    $cmd\n";
	    if (system($cmd)) {
		# Add members into groups using the "net localgroup /add" command.
		$cmd = "$NET localgroup $gname $login /add";
		##print "    $cmd\n";
		if (system($cmd) != 0) {
		    warning("os_usermod error ($cmd)\n");
		}
	    }
	}
    }
420

Russ Fish's avatar
Russ Fish committed
421
    $cmd = "echo -e '$pswd\\n$pswd' | passwd $login >& /dev/null";
422
423
424
425
    ##print "    $cmd\n";
    if (system($cmd) != 0) {
	warning("os_usermod error ($cmd)\n");
    }
426
427
428
429
430
431
432
433
434
}

#
# Add a user.
# 
sub os_useradd($$$$$$$$$)
{
    my($login, $uid, $gid, $pswd, $glist, $homedir, $gcos, $root, $shell) = @_;

435
436
    # Groups have to be created before we can add members.
    my $gname = $groupsByGid{$gid};
437
    warning("Missing group name for gid $gid.\n")
438
439
440
441
442
443
444
445
446
447
	if (!$gname);
    $groupMembers{$gname} .= "$login ";
    $groupMembers{'Administrators'} .= "$login "
	if ($root);
    foreach my $gid (split(/,/, $glist)) {
	$gname = $groupsByGid{$gid};
	if ($gname) {
	    $groupMembers{$gname} .= "$login ";
	}
	else {
448
	    warning("Missing group name for gid $gid.\n");
449
	}
450
    }
451
		     
452
453
    # Map the shell into a full path.
    $shell = MapShell($shell);
454
455
456
    # Change the ones that are different from the default from mkpasswd, /bin/bash.
    print USERSHELLS "/^$login:/s|/bin/bash\$|$shell|\n"
	if ($shell !~ "/bin/bash");
457

458
459
460
    # Use the leading 8 chars of the Unix MD5 passwd hash as a known random
    # password, both here and in Samba.  Skip over a "$1$" prefix.
    my $pwd = $pswd;
461
    $pwd =~ s/^(\$1\$)(.{8}).*/$2/;
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
    
    print WINUSERS "$login,$gcos,$pwd,,,,,\r\n";

    return 0;
}

#
# Finish the input for the addusers command.
#
sub os_accounts_end()
{
    # Dump out the group *creation* lines.
    print WINUSERS "[Local]\r\n";
    foreach my $grp (@groupNames) {
	# Ignore group membership here.  See "net localgroup" below.
	print WINUSERS "$grp,Emulab $grp group,\r\n";
    }
    close WINUSERS;
480
    close USERSHELLS;
481
482
483
484
485
486
487
488
489
       
    # Create the whole batch of groups and accounts listed in the file.
    # /p options: Users don't have to change passwords, and they never expire.
    print "Creating the Windows users and groups.\n";
    my $winfile = "C:/cygwin$winusersfile";
    $winfile =~ s|/|\\|g;
    my $cmd = "$ADDUSERS /c '$winfile' /p:le";
    ##print "    $cmd\n";
    if (system($cmd) != 0) {
490
	warning("AddUsers error ($cmd)\n");
491
492
	return -1;
    }
493
494
495
496
497
498
499
500
501

    # Add members into groups using the "net localgroup /add" command.
    # (Addusers only creates groups, it can't add a user to an existing group.)
    while (my($grp, $members) = each %groupMembers) {
	foreach my $mbr (split(/ /,$members)) {
	    print "  Adding $mbr to $grp.\n";
	    my $cmd = "$NET localgroup $grp $mbr /add > /dev/null";
	    ##print "    $cmd\n";
	    if (system($cmd) != 0) {
502
		warning("net localgroup error ($cmd)\n");
503
504
505
506
507
	    }
	}
    }

    # Make the CygWin /etc/passwd and /etc/group files match Windows.
508
    # Note that the group membership is not reported into the CygWin files.
509
    return os_accounts_sync();
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
}

#
# Remove a homedir. Might someday archive and ship back.
#
sub os_homedirdel($$)
{
    return 0;
}

#
# Create a directory including all intermediate directories.
#
sub os_mkdir($$)
{
    my ($dir, $mode) = @_;

    if (system("$MKDIR -p -m $mode $dir")) {
	return 0;
    }
    return 1;
}

#
# OS Dependent configuration. 
# 
sub os_setup()
{
    return 0;
}
    
#
# OS dependent, routing-related commands
#
sub os_routing_enable_forward()
{
Mike Hibler's avatar
Mike Hibler committed
546
    return "";
547
548
549
550
}

sub os_routing_enable_gated($)
{
Mike Hibler's avatar
Mike Hibler committed
551
    return "";
552
553
554
555
556
557
558
559
}

sub os_routing_add_manual($$$$$;$)
{
    my ($routetype, $destip, $destmask, $gate, $cost, $rtabid) = @_;
    my $cmd;

    if ($routetype eq "host") {
Mike Hibler's avatar
Mike Hibler committed
560
	$cmd = "$ROUTE add $destip $gate";
561
    } elsif ($routetype eq "net") {
Mike Hibler's avatar
Mike Hibler committed
562
	$cmd = "$ROUTE add $destip mask $destmask $gate";
563
    } elsif ($routetype eq "default") {
Mike Hibler's avatar
Mike Hibler committed
564
	$cmd = "$ROUTE add 0.0.0.0 $gate";
565
    } else {
566
	warning("Bad routing entry type: $routetype\n");
567
568
569
570
571
572
573
574
575
576
577
578
	$cmd = "";
    }

    return $cmd;
}

sub os_routing_del_manual($$$$$;$)
{
    my ($routetype, $destip, $destmask, $gate, $cost, $rtabid) = @_;
    my $cmd;

    if ($routetype eq "host") {
Mike Hibler's avatar
Mike Hibler committed
579
	$cmd = "$ROUTE delete $destip";
580
    } elsif ($routetype eq "net") {
Mike Hibler's avatar
Mike Hibler committed
581
	$cmd = "$ROUTE delete $destip";
582
    } elsif ($routetype eq "default") {
Mike Hibler's avatar
Mike Hibler committed
583
	$cmd = "$ROUTE delete 0.0.0.0";
584
    } else {
585
	warning("Bad routing entry type: $routetype\n");
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
	$cmd = "";
    }

    return $cmd;
}

# Map a shell name to a full path using /etc/shells
sub MapShell($)
{
   my ($shell) = @_;

   if ($shell eq "") {
       return $DEFSHELL;
   }

   my $fullpath = `grep '/${shell}\$' $SHELLS`;

   if ($?) {
       return $DEFSHELL;
   }

   # Sanity Check
   if ($fullpath =~ /^([-\w\/]*)$/) {
       $fullpath = $1;
   }
   else {
       $fullpath = $DEFSHELL;
   }
   return $fullpath;
}

617
sub os_samba_mount($$$)
618
619
620
{
    my ($local, $host, $verbose) = @_;

621
    # Unmount each one first, ignore errors.
Russ Fish's avatar
Russ Fish committed
622
    system("$UMOUNT $local");
623

624
625
    # Make the CygWin mount from the Samba path to the local mount point directory.
    my $sambapath = $local;
626
    $sambapath =~ s|^/proj/(.*)|proj-$1|;
Russ Fish's avatar
Typo.    
Russ Fish committed
627
    $sambapath =~ s|^/groups/(.*)/(.*)|$1-$2|;
628
629
    $sambapath =~ s|.*/(.*)|$1|;
    $sambapath = "//$host/$sambapath";
630
631
    if (! -e $local) {
	print "os_samba_mount: Making CygWin '$local' mount point directory.\n"
632
	    if ($verbose);
633
634
	if (! os_mkdir($local, "0755")) {  # Will make whole path if necessary.
	    warning("os_samba_mount: Could not make mount point $local.\n");
635
636
	}
    }
637
638
    elsif (! -d $local) {
	warning("os_samba_mount: Mount point $local is not a directory.\n");
639
    }
640
    print "Mounting '$local' from '$sambapath'.\n"
641
	if ($verbose);
642
643
644
645
646

    # If we don't turn on the -E/--no-executable flag, CygWin mount warns us:
    #     mount: defaulting to '--no-executable' flag for speed since native path
    #            references a remote share.  Use '-f' option to override.
    # Even with -E, exe's and scripts still work properly, so put it in.
647
    $cmd = "$MOUNT -f -E $sambapath $local";
648
    if (system($cmd) != 0) {
649
	warning("os_samba_mount: Failed, $cmd.\n");
650
651
652
653
    }
}

# Extract the local mount point from a remote NFS mount path.
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
sub os_mountlocal($)
{
    my ($remote) = @_;
    my $local = $remote;
    $local =~ s|^.*:||;			# Remove server prefix.
    $local =~ s|^/q/proj/|/proj/|;	# Remove /q prefix from /proj.
    return $local;
}

# Execute a noisy bash command, throwing away the output unless we ask for it.
sub os_noisycmd($$)
{
    my ($cmd, $verbose) = @_;
    my $bashcmd = "$BASH -c '$cmd'" . ($verbose ? "" : " > /dev/null");
    my $ret = system($bashcmd);
    ##print "os_noisycmd cmd '$cmd', ret $ret\n";
    return $ret
}

sub os_fwconfig_line($@)
{
    my ($fwinfo, @fwrules) = @_;
    my ($upline, $downline);
677
    my $errstr = "*** WARNING: Windows firewall not implemented\n";
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715

    warn $errstr;
    $upline = "echo $errstr; exit 1";
    $downline = "echo $errstr; exit 1";

    return ($upline, $downline);
}

sub os_fwrouteconfig_line($$$)
{
    my ($orouter, $fwrouter, $routestr) = @_;
    my ($upline, $downline);

    #
    # XXX assume the original default route should be used to reach servers.
    #
    # For setting up the firewall, this means we create explicit routes for
    # each host via the original default route.
    #
    # For tearing down the firewall, we just remove the explicit routes
    # and let them fall back on the now re-established original default route.
    #
    $upline  = "for vir in $routestr; do\n";
    $upline .= "        $ROUTE delete \$vir >/dev/null 2>&1\n";
    $upline .= "        $ROUTE add -host \$vir gw $orouter || {\n";
    $upline .= "            echo \"Could not establish route for \$vir\"\n";
    $upline .= "            exit 1\n";
    $upline .= "        }\n";
    $upline .= "    done";

    $downline  = "for vir in $routestr; do\n";
    $downline .= "        $ROUTE delete \$vir >/dev/null 2>&1\n";
    $downline .= "    done";

    return ($upline, $downline);
}

1;