Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1662 lines
43 KiB

  1. package FRSSUP;
  2. use strict;
  3. my $DEBUG_OBJ_CREATE = 0;
  4. my $DEBUG_OBJ_DEATH = 0;
  5. my $DEBUG_VERBOSE = 0; # set this to one to see schedules generated.
  6. my $METHOD_REPEAT = 1;
  7. my $METHOD_CUSTOM = 2;
  8. my %Days = ( "SU"=>0, "MO"=>1, "TU"=>2, "WE"=>3, "TH"=>4, "FR"=>5, "SA"=>6);
  9. my %Qtrs = ( "00"=>0, "15"=>1, "30"=>2, "45"=>3);
  10. my @NumToDay = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
  11. my %FRS_TYPE_MAP = (SYSVOL => 2, DFS => 3, OTHER => 4);
  12. my %SymbolTable = ();
  13. my $Usage = "
  14. Generic Usage: $0 [cmd options] \> output
  15. Process the FRSConfig generated configuration script.
  16. Command line options must be prefixed with a dash.
  17. -verbose=all : display all debug output.
  18. -Dvarname=value : define a program input parameter. The program can
  19. retrieve the value with the reference \$CMD_VARS{\"varname\"}.
  20. varname is case sensitive.
  21. ";
  22. #
  23. # TODO:
  24. #
  25. # support /DC param to specify the DC to bind to.
  26. #
  27. sub EmitMkdso {
  28. #
  29. # construct the mkdsoe command.
  30. #
  31. my $outstr = join(" ", @_);
  32. print $outstr, "\n";
  33. }
  34. sub EmitMkdsx {
  35. #
  36. # construct the mkdsox command.
  37. #
  38. my $outstr = join(" ", @_);
  39. print $outstr, "\n";
  40. }
  41. sub FRS_TIME_TO_QTRHR {
  42. #
  43. # Convert a time in the format '[dd:]hh[:qq']
  44. # dd is first 2 letters of the day of the week,
  45. # hh is the hour (24 hour format) and
  46. # qq is the quarter-hour. 00 means on the hour, 15 means quarter past
  47. # 30 means half past, 45 means 3/4 past.
  48. #
  49. # Returns an integer between 0 and 4*24*7-1.
  50. #
  51. my $TimeArg = shift;
  52. my ($a, $b, $c, $rest, $Time, $day, $hr, $qtrhr);
  53. $day = 'SU'; $hr = 0; $qtrhr = '00';
  54. $Time = $TimeArg;
  55. $Time =~ s/^[\s:]+//; # Strip any leading and trailing ":"
  56. $Time =~ s/[\s:]+$//;
  57. $Time = uc($Time).":ZZ:ZZ:ZZ";
  58. ($a, $b, $c, $rest) = split(":", $Time);
  59. if ($a ne "ZZ") { # null or blank string
  60. if ($b eq "ZZ") {
  61. $hr = $a; # hh
  62. } else {
  63. if ($c eq "ZZ") { # dd:hh or hh:qq
  64. if (defined $Days{$a}) {
  65. $day = $a; $hr = $b; # dd:hh
  66. } else {
  67. $hr = $a; $qtrhr = $b; # hh:qq
  68. }
  69. } else {
  70. $day = $a; $hr = $b; $qtrhr = $c; # dd:hh:qq
  71. }
  72. }
  73. } else {
  74. print "Invalid time: '$TimeArg'\n";
  75. return 0;
  76. }
  77. #
  78. # REPL_INTERVAL can be > 24 hours so for now skip the check.
  79. #
  80. #if ($hr > 23) {
  81. # print "Hour out of range: '$hr' for arg '$TimeArg'\n";
  82. # $hr = 0;
  83. #}
  84. #print "'$day' '$hr' '$qtrhr'\n";
  85. $Time = (($Days{$day}*24 + $hr) * 4) + $Qtrs{$qtrhr};
  86. #print "TimeToQtrhr: $TimeArg = $Time\n";
  87. return $Time;
  88. }
  89. sub Decode7x24 {
  90. #
  91. # take a comma seperated string composed of time ranges (see FRS_SCHEDULE)
  92. # and compose a bit vector of length 7*24*4 bits.
  93. #
  94. my $TimeZoneShift = shift;
  95. my $fields = shift;
  96. my ($field, $adj, $from, $to, $i, $str, $vector, $d);
  97. #
  98. # allocate the entire vector.
  99. #
  100. $vector = "";
  101. vec ($vector, 4*24*7-1, 1) = 0;
  102. foreach $field (split(",", $fields)) {
  103. if ($field =~ m/-/) {
  104. ($from, $to) = split("-", $field);
  105. #print "from: '$from' to: '$to'\n";
  106. $from = &FRS_TIME_TO_QTRHR($from);
  107. $to = &FRS_TIME_TO_QTRHR($to);
  108. } else {
  109. $to = $from = &FRS_TIME_TO_QTRHR($field);
  110. }
  111. if ($from > $to) {
  112. print "Invalid range (from > to) in argument: $field\n";
  113. } elsif ($to >= 4*7*24) {
  114. print "Invalid range (to>=4*7*24) in argument: $field\n";
  115. } else {
  116. #
  117. # Don't apply TIME_ZONE shift here. That gets done after the
  118. # final schedule is generated.
  119. #
  120. for ($i=$from; $i<$to; $i++) {
  121. vec($vector, $i, 1) = 1;
  122. }
  123. }
  124. }
  125. #
  126. # convert to a hex string for display.
  127. #
  128. if ($DEBUG_OBJ_CREATE) {
  129. $str = unpack( "h*", $vector);
  130. for ($d=0; $d<7; $d++) {
  131. printf ("%s : %s\n", $NumToDay[$d], substr($str, $d*24, 24));
  132. }
  133. }
  134. return $vector;
  135. }
  136. sub FRS_COUNT_SET {
  137. #
  138. # Return a count of the number of objects in $SetName
  139. # SET=>set array ref.
  140. #
  141. my %args = (
  142. SET => undef,
  143. @_, # arg pair list
  144. );
  145. my $rArray = $args{SET};
  146. my ($k, $v);
  147. if ($DEBUG_OBJ_CREATE) {
  148. while ( ($k, $v) = each %args ) { print "\t$k => '$v'\n"; }
  149. }
  150. return scalar(@$rArray) if (defined($rArray));
  151. return 0;
  152. }
  153. sub AddToSet {
  154. my $SetName = shift;
  155. my $Ref = shift;
  156. if (!exists($SymbolTable{$SetName})) {
  157. $SymbolTable{$SetName} = [];
  158. }
  159. push @{ $SymbolTable{$SetName} }, $Ref;
  160. return;
  161. }
  162. sub FRS_SET {
  163. #
  164. # Return the value of the SET key/value pair.
  165. # SET=>set array ref.
  166. #
  167. my %args = (
  168. SET => undef,
  169. @_, # arg pair list
  170. );
  171. return $args{SET};
  172. }
  173. sub FRS_SHOW {
  174. #
  175. # Display the contents of the Specified set.
  176. # SET=>set array ref.
  177. #
  178. my %args = (
  179. SET => undef,
  180. @_, # arg pair list
  181. );
  182. my $i;
  183. for $i (0 .. $#{ $args{SET} }) {
  184. print "\t$i = $args{SET}[$i]\n";
  185. &PrintHash( $args{SET}[$i] );
  186. }
  187. return ;
  188. }
  189. sub SelectSet {
  190. #
  191. # Return a ref to the array containing the objects in $SetName
  192. #
  193. my $SetName = shift;
  194. if (exists($SymbolTable{$SetName})) {
  195. return $SymbolTable{$SetName};
  196. }
  197. return;
  198. }
  199. sub DeleteSet {
  200. #
  201. # Deletes the hash entry and the array containing the objects in $SetName
  202. #
  203. my $SetName;
  204. foreach $SetName (@_) {
  205. print "## Removing set: $SetName\n" if ($DEBUG_OBJ_DEATH);
  206. undef $SymbolTable{$SetName} if (exists($SymbolTable{$SetName}));
  207. }
  208. return;
  209. }
  210. sub PrintHash {
  211. my $ref = shift;
  212. my ($k, $v);
  213. print "\n";
  214. while ( ($k, $v) = each %$ref ) {
  215. print "\t\t$k => '$v'\n";
  216. }
  217. }
  218. sub DumpSet {
  219. my ($SetName, $i, $k1, $v1);
  220. foreach $SetName (@_) {
  221. print "$SetName dump:\n";
  222. for $i (0 .. $#{ $SymbolTable{$SetName} }) {
  223. print "\t$i = $SymbolTable{$SetName}[$i]\n";
  224. &PrintHash( $SymbolTable{$SetName}[$i] );
  225. }
  226. }
  227. }
  228. sub DumpAllSets {
  229. DumpSet keys %SymbolTable;
  230. }
  231. sub SupTrim {
  232. my @str = @_;
  233. for (@str) {s/^\s+//; s/\s+$//;}
  234. return wantarray ? @str : $str[0];
  235. }
  236. sub ParseSwitch {
  237. my $record = shift;
  238. my @result = ();
  239. #
  240. # split out the left hand side and right hand side of a switch parameter
  241. # seperated by "=".
  242. # backslash can be used as an escape character and quoted strings are skipped
  243. # (i.e. they are not matched for a "=" separator)
  244. #
  245. $record = SupTrim($record);
  246. while ( $record =~ m{
  247. ( # Start of captured result
  248. (?:[^\"\\\=]* # swallow chars up to " or \ or /
  249. (?: # followed by 3 alternatives
  250. (?=\=|$) # 1. positive lookahead assertion for = or eos ends match
  251. |(?:\\.) # 2. if backslash, swallow it + next char
  252. |(?:\" # 3. if leading quote then find end of quoted
  253. # string but respect backslash escape char.
  254. (?:[^\"\\]* # swallow up to next " or \ if any
  255. (?:\\. # if prev ended on \ then swallow it + next char
  256. [^\"\\]* # continue to next quote or \, if any
  257. )* # loop if we hit \
  258. )
  259. \"? # consume trailing quote, if any. could be eos
  260. )
  261. ) # end of 3 alternatives
  262. )+ # continue after quoted string or \
  263. ) \=? # end match with next = (if any) ends captured result
  264. | ([^\=]+) /? # no quotes up to next =, if any, or eos
  265. | \= # eat extra =
  266. }gx ) {
  267. print " pre:'$`' match:'$+' post:'$'' lastparen:'$+' \n" if $DEBUG_VERBOSE;
  268. # print "Switch match:'$+' \t\t lastparen:'$+' \n";
  269. push (@result, SupTrim($+)) if (SupTrim($+) ne '');
  270. }
  271. push (@result, undef) if scalar(@result) eq 1;
  272. return @result;
  273. }
  274. sub ProcessCmdLine{
  275. my $CMD_VARS = shift;
  276. my $CMD_PARS = shift;
  277. my ($k, $v, $lhs, $rhs, @CmdPars, $param);
  278. #
  279. # We expect the CMD_VARS and CMD_PARS to be defined in package main.
  280. #
  281. $k = 0;
  282. for ($v=0; $v < scalar @ARGV; $v++) {
  283. if ($ARGV[$v] =~ m;^[-/];) {
  284. push @CmdPars, $ARGV[$v];
  285. } else {
  286. $ARGV[$k++] = $ARGV[$v];
  287. }
  288. }
  289. $#ARGV = $k-1; # eliminate the args that were put in CmdPars.
  290. foreach $param (@CmdPars) {
  291. if ($param =~ s;^[-/][Dd];;) {
  292. ($lhs, $rhs) = ParseSwitch($param);
  293. $CMD_VARS->{$lhs} = $rhs;
  294. } else {
  295. $param =~ s!^[-/]!!;
  296. ($lhs, $rhs) = ParseSwitch($param);
  297. if (!defined $rhs) {
  298. $rhs = '';
  299. }
  300. $CMD_PARS->{lc($lhs)} = $rhs;
  301. }
  302. }
  303. print "## Command line defined variables.\n";
  304. while ( ($k, $v) = each %$CMD_VARS ) { print "##\t$k => '$v'\n"; }
  305. print "## Command line defined parameters.\n";
  306. while ( ($k, $v) = each %$CMD_PARS ) { print "##\t$k => '$v'\n"; }
  307. if (exists $CMD_PARS->{"?"} || exists $CMD_PARS->{"h"}) {
  308. print STDERR $Usage;
  309. }
  310. }
  311. sub CheckForHelp {
  312. my $CMD_PARS = shift; # ref to the CMD_PARS hash
  313. my $ScriptUsage = shift; # ref to the callers help string.
  314. if (exists $CMD_PARS->{"?"} || exists $CMD_PARS->{"h"}) {
  315. print STDERR $$ScriptUsage;
  316. exit;
  317. }
  318. }
  319. sub ShowHelp {
  320. my $ErrorString = shift; # Error message.
  321. my $ScriptUsage = shift; # ref to the callers help string.
  322. print STDERR $ErrorString, "\n\n";
  323. print STDERR $$ScriptUsage;
  324. exit;
  325. }
  326. package FRS_SETTINGS;
  327. use strict;
  328. #++
  329. # Package Description:
  330. # Define state and methods for an FRS Replica Set Settings object.
  331. #
  332. # State:
  333. # DN => 'Fully qualified DN of container in which to create Settings obj',
  334. # ONAME => 'object name of this object',
  335. # BINDDC => computer name of DC on which to create this object.
  336. #
  337. # Methods:
  338. #
  339. #--
  340. sub New {
  341. #++
  342. # Routine Description:
  343. # Create an FRS_SETTINGS object.
  344. #
  345. # Arguments:
  346. # ClassName
  347. # Init args -- see _Init()
  348. #
  349. # Return Value:
  350. # FRS_SETTINGS object reference
  351. #
  352. #--
  353. my $ClassName = shift;
  354. my $Self = {};
  355. bless ($Self, $ClassName);
  356. $Self->_Init(@_);
  357. return $Self;
  358. }
  359. sub _Init {
  360. #++
  361. # Routine Description:
  362. # Init the new FRS_SETTINGS object.
  363. #
  364. # Arguments:
  365. # Self : Object reference
  366. # DN => 'Fully qualified DN of container in which to create Settings obj',
  367. # ONAME => 'object name of this object',
  368. #
  369. # Return Value:
  370. # void
  371. #
  372. #--
  373. my $Self = shift;
  374. my $k;
  375. my $v;
  376. print "\nFRS_SETTINGS:\n" if ($DEBUG_OBJ_CREATE);
  377. #
  378. # set private arguments
  379. #
  380. $Self->{Test} = 'Test';
  381. #
  382. # Set Default arguments
  383. #
  384. my %args = (
  385. DN => '',
  386. ONAME => '',
  387. BINDDC => '',
  388. @_, # arg pair list
  389. );
  390. #
  391. # set parameter arguments
  392. #
  393. if (@_) {
  394. #
  395. # Update DN.
  396. #
  397. $args{DN} = "$args{ONAME}\,$args{DN}";
  398. @$Self{keys %args} = values %args;
  399. }
  400. if ($DEBUG_OBJ_CREATE) {
  401. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  402. }
  403. return;
  404. }
  405. sub DESTROY {
  406. my $Self = shift;
  407. printf("FRS_SETTINGS $Self->{ONAME} dying at %s\n", scalar localtime) if ($DEBUG_OBJ_DEATH);
  408. }
  409. package FRS_REPLICASET;
  410. use strict;
  411. #++
  412. # Package Description:
  413. # Define state and methods for an FRS Replica Set object.
  414. #
  415. # State:
  416. # UNDER => 'object tag or ref of replica set object',
  417. # ONAME => 'object name of this object',
  418. # SCHED => schedule object ref
  419. # FLAGS => Flags dword
  420. # TYPE => Replica set type (SYSVOL(2), DFS(3), OTHER(4))
  421. # FILE_FILTER => "comma list of file wildcard strings to exclude"
  422. # DIR_FILTER => "comma list of file wildcard strings to exclude"
  423. # BINDDC => computer name of DC on which to create this object.
  424. # PRIMARY_MEMBER => 'object tag or ref of member object that is the primary member'
  425. #
  426. # Methods:
  427. #
  428. #--
  429. sub New {
  430. #++
  431. # Routine Description:
  432. # Create an FRS_REPLICASET object.
  433. #
  434. # Arguments:
  435. # ClassName
  436. # Init args -- see _Init()
  437. #
  438. # Return Value:
  439. # FRS_REPLICASET object reference
  440. #
  441. #--
  442. my $ClassName = shift;
  443. my $Self = {};
  444. bless ($Self, $ClassName);
  445. $Self->_Init(@_);
  446. return $Self;
  447. }
  448. sub _Init {
  449. #++
  450. # Routine Description:
  451. # Init the new FRS_REPLICASET object.
  452. #
  453. # Arguments:
  454. # Self : Object reference
  455. # UNDER => 'object tag or ref of replica set object',
  456. # ONAME => 'object name of this object',
  457. #
  458. # Return Value:
  459. # void
  460. #
  461. #--
  462. my $Self = shift;
  463. my ($k, $v, $TypeCode);
  464. print "\nFRS_REPLICASET:\n" if ($DEBUG_OBJ_CREATE);
  465. #
  466. # set private arguments
  467. #
  468. $Self->{Test} = 'Test';
  469. #
  470. # Set Default arguments
  471. #
  472. my %args = (
  473. UNDER => '',
  474. SCHED => 'ON',
  475. ONAME => '',
  476. FLAGS => 0,
  477. TYPE => 'DFS',
  478. FILE_FILTER => '~*,*.tmp,*.bak',
  479. DIR_FILTER => '',
  480. PRIMARY_MEMBER => '',
  481. DN => 'need dn',
  482. BINDDC => '',
  483. @_, # arg pair list
  484. );
  485. #
  486. # set parameter arguments
  487. #
  488. if (@_) {
  489. #
  490. # Update DN.
  491. #
  492. $args{DN} = "CN=$args{ONAME},$args{UNDER}->{DN}";
  493. @$Self{keys %args} = values %args;
  494. }
  495. if ($DEBUG_OBJ_CREATE) {
  496. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  497. }
  498. $TypeCode = $FRS_TYPE_MAP{ uc( $Self->{TYPE} ) };
  499. FRSSUP::EmitMkdso("mkdsoe /createset",
  500. (($Self->{BINDDC} ne '') ? "/DC $Self->{BINDDC}" : ""),
  501. "/ntfrssettingsdn \"$Self->{UNDER}->{DN}\"",
  502. "/setname \"$Self->{ONAME}\"",
  503. "/settype $TypeCode",
  504. ($Self->{FILE_FILTER} ne "") ? "/filefilter \"$Self->{FILE_FILTER}\"" : "",
  505. ($Self->{DIR_FILTER} ne "") ? "/directoryfilter \"$Self->{DIR_FILTER}\"" : "",
  506. ($Self->{PRIMARY_MEMBER} ne "") ? "/primarymember \"$Self->{PRIMARY_MEMBER}->{ONAME}\"" : "",
  507. );
  508. return;
  509. }
  510. sub DESTROY {
  511. my $Self = shift;
  512. printf("FRS_REPLICASET $Self->{ONAME} dying at %s\n", scalar localtime) if ($DEBUG_OBJ_DEATH);
  513. }
  514. package FRS_MEMBER;
  515. use strict;
  516. #++
  517. # Package Description:
  518. # Define state and methods for an FRS member object.
  519. #
  520. # State:
  521. # UNDER => 'object tag or ref of replica set object',
  522. # SERVER => Ref to FRS_SERVER object
  523. # ONAME => 'object name of this object',
  524. # BINDDC => computer name of DC on which to create this object.
  525. #
  526. # The following can be specified to override the values contained in SERVER.
  527. # COMPUTER => 'object tag or ref of computer object',
  528. # RP => "root path of replica tree on server",
  529. # SP => "staging path for this replica set on this server",
  530. # DNS_NAME => Computer name, e.g. "huba.hubsite.ajax.com");
  531. # WORKPATH => Working path value for subscriptions object if it is created.
  532. #
  533. # Methods:
  534. #
  535. #--
  536. sub New {
  537. #++
  538. # Routine Description:
  539. # Create an FRS_MEMBER object.
  540. #
  541. # Arguments:
  542. # ClassName
  543. # Init args -- see _Init()
  544. #
  545. # Return Value:
  546. # FRS_MEMBER object reference
  547. #
  548. # Example: FRS_MEMBER::New( UNDER=>"RSB", COMPUTER=>"HA", ONAME=>"MEMBER 1" );
  549. #--
  550. my $ClassName = shift;
  551. my $Self = {};
  552. bless ($Self, $ClassName);
  553. $Self->_Init(@_);
  554. return $Self;
  555. }
  556. sub _Init {
  557. #++
  558. # Routine Description:
  559. # Init the new FRS_MEMBER object.
  560. #
  561. # Arguments:
  562. # Self : Object reference
  563. # See above.
  564. #
  565. # Return Value:
  566. # void
  567. #
  568. #--
  569. my $Self = shift;
  570. my $k;
  571. my $v;
  572. print "\nFRS_MEMBER:\n" if ($DEBUG_OBJ_CREATE);
  573. #
  574. # set private arguments
  575. #
  576. $Self->{Test} = 'Test';
  577. #
  578. # Set Default arguments. Some defaults will come from the FRS_SERVER object.
  579. #
  580. my %args = (
  581. UNDER => '',
  582. SERVER => '',
  583. ONAME => '',
  584. MAKE_PRIMARY_MEMBER => '',
  585. DN => 'need dn',
  586. BINDDC => '',
  587. @_, # arg pair list
  588. );
  589. #
  590. # set parameter arguments
  591. #
  592. if (@_) {
  593. @$Self{keys %args} = values %args;
  594. }
  595. #
  596. # Provide defaults from FRS_SERVER arg if no caller supplied override.
  597. #
  598. while (($k, $v) = each % { $args{SERVER} }) {
  599. if ( !exists($Self->{$k}) || ($Self->{$k} eq '')) {
  600. $Self->{$k} = $v;
  601. }
  602. }
  603. #
  604. # Update DN.
  605. #
  606. $Self->{DN} = "CN=".$Self->{ONAME}.",".$Self->{UNDER}->{DN};
  607. if ($DEBUG_OBJ_CREATE) {
  608. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  609. }
  610. #
  611. # The member object.
  612. #
  613. FRSSUP::EmitMkdso("mkdsoe /createmember",
  614. (($Self->{BINDDC} ne '') ? "/DC $Self->{BINDDC}" : ""),
  615. (($Self->{MAKE_PRIMARY_MEMBER} ne '') ? "/makemeprimary" : ""),
  616. "/NtfrsSettingsDN \"$Self->{UNDER}->{UNDER}->{DN}\"",
  617. "/SetName \"$Self->{UNDER}->{ONAME}\"",
  618. "/ComputerName \"$Self->{COMPUTER}\"",
  619. "/MemberName \"$Self->{ONAME}\"",
  620. );
  621. #
  622. # The subscriber object.
  623. #
  624. FRSSUP::EmitMkdso("mkdsoe /createsubscriber",
  625. "/NtfrsSettingsDN \"$Self->{UNDER}->{UNDER}->{DN}\"",
  626. "/SetName \"$Self->{UNDER}->{ONAME}\"",
  627. "/ComputerName \"$Self->{COMPUTER}\"",
  628. "/MemberName \"$Self->{ONAME}\"",
  629. "/RootPath \"$Self->{RP}\"",
  630. "/StagePath \"$Self->{SP}\"",
  631. "/WorkingPath \"$Self->{WORKPATH}\"",
  632. );
  633. return;
  634. }
  635. sub DESTROY {
  636. my $Self = shift;
  637. printf("FRS_MEMBER $Self->{ONAME} dying at %s\n", scalar localtime) if ($DEBUG_OBJ_DEATH);
  638. }
  639. package FRS_CONNECTION;
  640. use strict;
  641. #++
  642. # Package Description:
  643. # Define state and methods for an FRS connection object.
  644. #
  645. # State:
  646. # TO => 'object tag of destination FRS member object',
  647. # FROM => 'object tag of the source's FRS member object',
  648. # ONAME => 'object name of this object',
  649. # SCHED => schedule object ref | ON | OFF
  650. # OPTIONS => Options dword
  651. # FLAGS => Flags dword
  652. # ENABLED => '[0 | 1]'
  653. # BINDDC => computer name of DC on which to create this object.
  654. # TIME_ZONE => '+- nn[:qq]' Timezone override adjustment to apply to schedule
  655. # 0 = GMT (default)
  656. #
  657. # If the NTDSCONN_OPT_TWOWAY_SYNC flag is set on the connection then
  658. # merge the schedule on this connection with the schedule on the connection
  659. # that is in the opposite direction and use the resultant schedule on the
  660. # connection in the opposite direction.
  661. #
  662. # The TO and FROM arguments refer to an FRS_MEMBER object. The SERVER argument
  663. # in the FRS_MEMBER object is used to acquire the DNS_NAME argument of the
  664. # FRS_SERVER object.
  665. #
  666. # Methods:
  667. #
  668. #--
  669. sub New {
  670. #++
  671. # Routine Description:
  672. # Create an FRS_CONNECTION object.
  673. #
  674. # Arguments:
  675. # ClassName
  676. # Init args -- see _Init()
  677. #
  678. # Return Value:
  679. # FRS_CONNECTION object reference
  680. #
  681. #--
  682. my $ClassName = shift;
  683. my $Self = {};
  684. bless ($Self, $ClassName);
  685. $Self->_Init(@_);
  686. return $Self;
  687. }
  688. sub _Init {
  689. #++
  690. # Routine Description:
  691. # Init the new FRS_CONNECTION object.
  692. #
  693. # Arguments:
  694. # Self : Object reference
  695. # UNDER => 'object tag or ref of replica set object',
  696. # ONAME => 'object name of this object',
  697. #
  698. # Return Value:
  699. # void
  700. #
  701. #--
  702. my $Self = shift;
  703. my ($k, $v, $Schedule);
  704. print "\nFRS_CONNECTION:\n" if ($DEBUG_OBJ_CREATE);
  705. #
  706. # set private arguments
  707. #
  708. $Self->{Test} = 'Test';
  709. #
  710. # Set Default arguments
  711. #
  712. my %args = (
  713. TO => '',
  714. FROM => '',
  715. ONAME => '',
  716. SCHED => {},
  717. OPTIONS => 0,
  718. FLAGS => 0,
  719. ENABLED => 1,
  720. BINDDC => '',
  721. @_, # arg pair list
  722. );
  723. #
  724. # set parameter arguments
  725. #
  726. if (@_) {
  727. #
  728. # Update DN.
  729. #
  730. $args{DN} = "CN=$args{ONAME},$args{TO}->{DN}";
  731. @$Self{keys %args} = values %args;
  732. }
  733. if ($DEBUG_OBJ_CREATE) {
  734. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  735. print "\n";
  736. }
  737. if ($args{SCHED} ne '') {
  738. #print "\tSCHED => $args{SCHED}\n";
  739. # get schedule from $args{SCHED}->{SCHEDULE}
  740. # Need to check the data type of $args{SCHED} for a string type with
  741. # a value of ON or OFF.
  742. # if it is a ref to a hash then it is a schedule object. CAN WE VERIFY
  743. # the object type is valid?
  744. #
  745. }
  746. #
  747. # Input paramters to mkdsxe.exe
  748. #
  749. # /v, Verbose mode.
  750. # /debug, Debug mode. No Writes to the DC.
  751. # N /dc, Name of the DC to connect to.
  752. #
  753. # /create Operation to be performed. only one of the 4 is allowed.
  754. # /update
  755. # /del
  756. # /dump
  757. #
  758. # /all, Perform the operation on all the connections to the toserver.
  759. # /all only works with /dump and /del.
  760. #
  761. # SN /name, Name of the connection to be created.
  762. # SN /enable, Connection is enabled.
  763. # /disable, Connection is disabled.
  764. # S /fromsite, Name of the site the 'from' server is in.
  765. # S /tosite, Name of the site the 'to' server is in.
  766. # S /fromserver, Name of the 'from' server.
  767. # S /toserver, Name of the 'to' server.
  768. # N /replicasetname, Name of the non-sysvol replica set.
  769. # N /fromcomputer, DNS name of the 'from' computer. /replicasetname needed.
  770. # N /tocomputer, DNS name of the 'to' computer. /replicasetname needed.
  771. #
  772. # /options <integer>, "Sum of the following options for connection.
  773. # "IsGenerated = 1
  774. # "TwoWaySync = 2
  775. # "OverrideNotifyDefault = 3
  776. # "UseNotify = 4
  777. #
  778. # SN /schedule <Interval> <Stagger> <Offset>, Schedule to create for the connection.
  779. # <Interval>, The desired interval between each sync with one source.
  780. # <Stagger>, Typically number of source DCs.
  781. # <Offset>, Typically the number of the source DC.
  782. #
  783. # /schedoverride, File with 7x24 vector of schedule override data.
  784. # /schedmask, File with 7x24 vector of schedule mask off data.
  785. # SchedOverride and SchedMask data are formatted as 2 ascii hex digits
  786. # for each schedule byte.
  787. #
  788. # Inputs are prefixed with an S or N. S means this input is required for the
  789. # creation of a sysvol replica set connection. N means this input is required
  790. # for a non-sysvol replica set.
  791. #
  792. if ($Self->{SCHED} eq 'ON') {
  793. $Schedule = '';
  794. } elsif ($Self->{SCHED} eq 'OFF') {
  795. $Schedule = '/Schedule 0 0 0';
  796. } else {
  797. #
  798. # Check for TIME_ZONE override for this connection.
  799. #
  800. if (defined $args{TIME_ZONE}) {
  801. FRS_SCHEDULE::FRS_APPLY_TIMEZONE(SCHED=>$Self->{SCHED},
  802. TIME_ZONE=>$args{TIME_ZONE});
  803. }
  804. #
  805. # Build the Custom schedule.
  806. #
  807. $Self->{SCHED}->BuildSchedule;
  808. $Schedule = "/CustomSchedule $Self->{SCHED}->{SCHEDULE}"
  809. }
  810. #
  811. # The connection object.
  812. #
  813. FRSSUP::EmitMkdsx("mkdsxe.exe /create",
  814. (($Self->{BINDDC} ne '') ? "/DC $Self->{BINDDC}" : ""),
  815. "/Name \"$Self->{ONAME}\"",
  816. "/ReplicaSetName \"$Self->{TO}->{UNDER}->{ONAME}\"",
  817. "/ToComputer \"$Self->{TO}->{SERVER}->{DNS_NAME}\"",
  818. "/FromComputer \"$Self->{FROM}->{SERVER}->{DNS_NAME}\"",
  819. ($Self->{ENABLED} ? "/enable" : "/disable"),
  820. $Schedule,
  821. );
  822. return;
  823. }
  824. sub DESTROY {
  825. my $Self = shift;
  826. printf("FRS_CONNECTION $Self->{ONAME} dying at %s\n", scalar localtime) if ($DEBUG_OBJ_DEATH);
  827. }
  828. package FRS_SCHEDULE;
  829. use strict;
  830. #++
  831. # Package Description:
  832. # Define state and methods for an FRS Schedule object.
  833. # A schedule is a 7x24 array of bytes (1 byte for each hour of the week)
  834. # The low four bits are used to select the quarter-hour.
  835. #
  836. # State:
  837. # TYPE => '[ONOFF | BANDWIDTH] # Only ONOFF schedules are supported.
  838. # REPL_INTERVAL => 'nn[:qq]' # Desired interval between start of repl cycle
  839. # REPL_DURATION => 'nn[:qq]' # Duration of of repl cycle
  840. # TIME_ZONE => '+- nn[:qq]' # Timezone adjustment to apply to time ranges
  841. # # 0 = GMT (default)
  842. # REPL_OFFSET => 'dd:nn[:qq'] # Offset from midnight sunday to start of
  843. # # periodic schedule (default is midnight sunday)
  844. # METHOD => 'REPEAT | CUSTOM' # Method used to construct the schedule
  845. # # CUSTOM means only use OVERRIDE and DISABLE
  846. # # arguments to make the schedule.
  847. # STAGGER => nnn:qq # The stagger amount to use by obj->STAGGER
  848. # OVERRIDE => 'time range' # Force schedule on during specified period
  849. # DISABLE => 'time range' # Force schedule off during specified period
  850. # # OVERRIDE and DISABLE can take multiple
  851. # # time ranges seperated by commas.
  852. # NAME => '' # Text string to identify schedule in printouts.
  853. #
  854. # qq : specifies a quarter hour. 00 means on the hour, 15 means quarter past
  855. # 30 means half past, 45 means 3/4 past.
  856. #
  857. # time range: A string describing the days and times during the week
  858. # when the related operation is applied.
  859. # The format is dd:hh[:qq]-dd:hh[:qq] where dd is the first
  860. # 2 letters of the day of the week, hh is the hour (24 hour format)
  861. # and qq is the quarter-hour.
  862. # So, mo:07:30-mo:18:00 refers to a time range starting
  863. # on mondays at 7:30 am and ending the same day at 6 pm.
  864. #
  865. # If the NTDSCONN_OPT_TWOWAY_SYNC flag is set on the connection then
  866. # merge the schedule on this connection with the schedule on the connection
  867. # that is in the opposite direction and use the resultant schedule on the
  868. # connection in the opposite direction.
  869. #
  870. #
  871. # Methods:
  872. #
  873. #--
  874. sub New {
  875. #++
  876. # Routine Description:
  877. # Create an FRS_SCHEDULE object.
  878. #
  879. # Arguments:
  880. # ClassName
  881. # Init args -- see _Init()
  882. #
  883. # Return Value:
  884. # FRS_SCHEDULE object reference
  885. #
  886. #--
  887. my $ClassName = shift;
  888. my $Self = {};
  889. bless ($Self, $ClassName);
  890. $Self->_Init(@_);
  891. return $Self;
  892. }
  893. sub _Init {
  894. #++
  895. # Routine Description:
  896. # Init the new FRS_SCHEDULE object.
  897. #
  898. # Arguments:
  899. # Self : Object reference
  900. # see above.
  901. #
  902. # Return Value:
  903. # void
  904. #
  905. #--
  906. my $Self = shift;
  907. my ($k, $v, $TimeZoneShift, $negative);
  908. print "\nFRS_SCHEDULE:\n" if ($DEBUG_OBJ_CREATE);
  909. #
  910. # Set Default arguments
  911. #
  912. my %args = (
  913. REPL_INTERVAL => "01", # One hour
  914. REPL_DURATION => "01", # One hour
  915. TIME_ZONE => 0, # no shift for GMT
  916. REPL_OFFSET => "00", # midnight sunday
  917. METHOD => $METHOD_REPEAT, # REPEATING | CUSTOM
  918. STAGGER => "00", # obj units are quarter-hours
  919. TYPE => 0, # ONOFF | BANDWIDTH
  920. NAME => '', # Text string to identify schedule in printouts.
  921. SCHED_DATA_CHANGE => 1, # Generate a new schedule when output is needed.
  922. @_, # arg pair list
  923. );
  924. #
  925. # set parameter arguments
  926. #
  927. if (@_) {
  928. @$Self{keys %args} = values %args;
  929. }
  930. if ($DEBUG_OBJ_CREATE) {
  931. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  932. }
  933. $Self->{STAGGER} = $args{STAGGER};
  934. #
  935. # First calc the timezone shift for use by Decode7x24 and BuildSchedule
  936. #
  937. $TimeZoneShift = $args{TIME_ZONE};
  938. $negative = ($TimeZoneShift =~ s/\s*\-//); # remove minus
  939. $TimeZoneShift =~ s/\s*\+//; # remove plus
  940. $Self->{TIME_ZONE} = &FRSSUP::FRS_TIME_TO_QTRHR($TimeZoneShift);
  941. if ($negative) {
  942. $Self->{TIME_ZONE} = 0 - $Self->{TIME_ZONE};
  943. }
  944. #
  945. # Convert times to Quarter hour units.
  946. #
  947. $Self->{REPL_INTERVAL} = &FRSSUP::FRS_TIME_TO_QTRHR($args{REPL_INTERVAL});
  948. $Self->{REPL_DURATION} = &FRSSUP::FRS_TIME_TO_QTRHR($args{REPL_DURATION});
  949. $Self->{REPL_OFFSET} = &FRSSUP::FRS_TIME_TO_QTRHR($args{REPL_OFFSET});
  950. #
  951. # Build override and disable masks.
  952. #
  953. if (defined $args{OVERRIDE} && $args{OVERRIDE} ne '') {
  954. undef $Self->{OVERRIDE};
  955. # convert time ranges to a 7x24x4 array.
  956. print "\tOVERRIDE => $args{OVERRIDE}\n" if ($DEBUG_OBJ_CREATE);
  957. $Self->{OVERRIDE} = &FRSSUP::Decode7x24($Self->{TIME_ZONE}, $args{OVERRIDE});
  958. }
  959. if (defined $args{DISABLE} && $args{DISABLE} ne '') {
  960. undef $Self->{DISABLE};
  961. # convert time ranges to a 7x24x4 array.
  962. print "\tDISABLE => $args{DISABLE}\n" if ($DEBUG_OBJ_CREATE);
  963. $Self->{DISABLE} = &FRSSUP::Decode7x24($Self->{TIME_ZONE}, $args{DISABLE});
  964. }
  965. $Self->{SCHED_DATA_CHANGE} = 1;
  966. return;
  967. }
  968. #
  969. # FRS_STAGGER_BY(/SCHED=SC1 /ADJUST=n)
  970. #
  971. # FRS_SCHEDULE->StaggerBy( &SelectSet("SC1")->[0], $Adjust);
  972. # or
  973. # &SelectSet("SC1")->[0]->StaggerBy ($Adjust);
  974. #
  975. sub FRS_STAGGER_BY {
  976. my $Self; # = shift;
  977. my ($k, $v);
  978. #
  979. # Set Default arguments
  980. #
  981. my %args = (
  982. ADJUST => "00",
  983. SCHED => '',
  984. @_, # arg pair list
  985. );
  986. if (@_) {
  987. $Self = $args{SCHED};
  988. }
  989. return if ($Self eq '');
  990. if ($DEBUG_OBJ_CREATE) {
  991. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  992. }
  993. #
  994. # Convert $args{ADJUST} to quarter-hour units.
  995. #
  996. my $Adjust = FRSSUP::FRS_TIME_TO_QTRHR($args{ADJUST});
  997. #
  998. # Increment the schedule offset by the stagger amount and calc new schedule.
  999. #
  1000. $Self->{REPL_OFFSET} += $Adjust;
  1001. $Self->{SCHED_DATA_CHANGE} = 1;
  1002. }
  1003. #
  1004. # FRS_STAGGER(/SCHED=SC1)
  1005. #
  1006. # FRS_SCHEDULE->Stagger( &SelectSet("SC1")->[0]);
  1007. #
  1008. sub FRS_STAGGER {
  1009. my $Self;
  1010. my $Adjust;
  1011. my ($k, $v);
  1012. #
  1013. # Set Default arguments
  1014. #
  1015. my %args = (
  1016. SCHED => '',
  1017. @_, # arg pair list
  1018. );
  1019. #
  1020. # set parameter arguments
  1021. #
  1022. if (@_) {
  1023. @$Self{SCHED} = $args{SCHED};
  1024. $Self = $args{SCHED};
  1025. }
  1026. return if ($Self eq '');
  1027. if ($DEBUG_OBJ_CREATE) {
  1028. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  1029. }
  1030. $Adjust = $Self->{STAGGER};
  1031. FRS_STAGGER_BY (SCHED=>$Self, ADJUST=>$Adjust);
  1032. }
  1033. #
  1034. # FRS_APPLY_TIMEZONE(/SCHED=SC1 /TIME_ZONE=n)
  1035. #
  1036. # FRS_SCHEDULE->FRS_APPLY_TIMEZONE( &SelectSet("SC1")->[0], $Adjust);
  1037. # or
  1038. # &SelectSet("SC1")->[0]->FRS_APPLY_TIMEZONE ($Adjust);
  1039. #
  1040. sub FRS_APPLY_TIMEZONE {
  1041. my $Self;
  1042. my ($k, $v, $negative, $TimeZoneShift);
  1043. #
  1044. # Set Default arguments
  1045. #
  1046. my %args = (
  1047. SCHED => '',
  1048. TIME_ZONE => '',
  1049. @_, # arg pair list
  1050. );
  1051. #while ( ($k, $v) = each %args ) { print "\t$k => '$v'\n"; }
  1052. if (@_) {
  1053. $Self = $args{SCHED};
  1054. }
  1055. return if (($Self eq '') || ($args{TIME_ZONE} eq ''));
  1056. if ($DEBUG_OBJ_CREATE) {
  1057. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  1058. }
  1059. #
  1060. # Convert $args{TIME_ZONE} to quarter-hour units.
  1061. #
  1062. $TimeZoneShift = $args{TIME_ZONE};
  1063. $negative = ($TimeZoneShift =~ s/\s*\-//); # remove minus
  1064. $TimeZoneShift =~ s/\s*\+//; # remove plus
  1065. $args{TIME_ZONE} = &FRSSUP::FRS_TIME_TO_QTRHR($TimeZoneShift);
  1066. if ($negative) {
  1067. $args{TIME_ZONE} = 0 - $args{TIME_ZONE};
  1068. }
  1069. #
  1070. # nothing to do if timezone unchanged.
  1071. #
  1072. return if ($args{TIME_ZONE} == $Self->{TIME_ZONE});
  1073. #
  1074. # Build the new schedule.
  1075. #
  1076. $Self->{TIME_ZONE} = $args{TIME_ZONE};
  1077. $Self->{SCHED_DATA_CHANGE} = 1;
  1078. }
  1079. sub BuildSchedule {
  1080. my $Self = shift;
  1081. my ($i, $adj, $endtime, $vector, $tzvector, $intervalExpired, $j, $Q);
  1082. my ($skipped, $span, $FirstPeriodGen);
  1083. my ($LastReplPeriod, $rpx, $CheckReplPeriodStart, $ReplPeriod);
  1084. my $interval = $Self->{REPL_INTERVAL};
  1085. my $duration = $Self->{REPL_DURATION};
  1086. my $offset = $Self->{REPL_OFFSET};
  1087. my $stagger = $Self->{STAGGER};
  1088. my $TimeZoneShift = $Self->{TIME_ZONE};
  1089. $vector = "";
  1090. vec ($vector, 4*24*7-1, 1) = 0;
  1091. $FirstPeriodGen = 0;
  1092. #
  1093. # Only recalc schedule if one of the operands changed.
  1094. #
  1095. if (!$Self->{SCHED_DATA_CHANGE}) {
  1096. #$Self->Print() if $DEBUG_VERBOSE;
  1097. return;
  1098. }
  1099. #
  1100. # Build new schedule using the current parameters.
  1101. #
  1102. if ($Self->{METHOD} == $METHOD_REPEAT) {
  1103. if ($interval == 0) {
  1104. print "\n\nERROR - Interval is invalid ($interval), no schedule produced.\n\n";
  1105. return;
  1106. }
  1107. $ReplPeriod = [];
  1108. $rpx = -1;
  1109. if ($interval > $duration) {
  1110. $rpx = 0;
  1111. if (defined $Self->{REPL_PERIOD_START}) {
  1112. $CheckReplPeriodStart = 1;
  1113. $LastReplPeriod = $Self->{REPL_PERIOD_START};
  1114. print "LastReplPeriod = ", join(", ", @$LastReplPeriod), "\n";;
  1115. }
  1116. }
  1117. #
  1118. # Build the repeating schedule first. Remember the end time so we
  1119. # know when to stop.
  1120. #
  1121. $Q = $offset - 1;
  1122. if ($Q >= 4*24*7) {
  1123. $Q = $Q - 4*24*7;
  1124. } elsif ($Q < 0) {
  1125. $Q = $Q + 4*24*7;
  1126. }
  1127. $endtime = $Q;
  1128. $Q = $Q + 1;
  1129. if ($Q >= 4*24*7) {$Q = 0;}
  1130. $i = 0;
  1131. $intervalExpired = 0;
  1132. if ($DEBUG_VERBOSE) {
  1133. print "\n## **** Q=$Q, offset=$offset, TimeZoneShift=$TimeZoneShift, interval=$interval \n";
  1134. }
  1135. QTR_HOUR: while ($i < 4*24*7) {
  1136. if ($intervalExpired <= 0) {
  1137. if ($DEBUG_VERBOSE) {
  1138. print "\n## **** Q=$Q, i=$i, offset=$offset, intervalExpired=$intervalExpired\n";
  1139. }
  1140. #
  1141. # If this replication period overlaps any disabled region of
  1142. # the schedule then scan past the disabled portion and continue
  1143. # Quarter Hour loop from there.
  1144. #
  1145. if (defined $Self->{DISABLE}) {
  1146. $adj = $Q;
  1147. $skipped = 0;
  1148. $span = $duration;
  1149. while (($span > 0) && (vec($Self->{DISABLE}, $adj, 1) == 0)) {
  1150. last if ($adj == $endtime);
  1151. if (++$adj >= 4*24*7) {$adj = 0;}
  1152. --$span;
  1153. }
  1154. if ($span > 0) {
  1155. #
  1156. # Open region was not large enough.
  1157. #
  1158. $skipped += ($duration - $span);
  1159. while (vec($Self->{DISABLE}, $adj, 1) == 1) {
  1160. ++$skipped;
  1161. last if ($adj == $endtime);
  1162. if (++$adj >= 4*24*7) {$adj = 0;}
  1163. }
  1164. }
  1165. if ($skipped > 0) {
  1166. #
  1167. # Need to advance the offset if we are still trying to
  1168. # generate the first replication period in the schedule.
  1169. #
  1170. if (!$FirstPeriodGen) {
  1171. $offset += $skipped;
  1172. if ($offset >= 4*24*7) {$offset = $offset - 4*24*7;}
  1173. $Self->{REPL_OFFSET} = $offset;
  1174. }
  1175. $Q += $skipped;
  1176. if ($Q >= 4*24*7) {$Q = $Q - 4*24*7;}
  1177. $intervalExpired -= $skipped;
  1178. #
  1179. # Go check the size of the next open region.
  1180. #
  1181. $i += $skipped;
  1182. next QTR_HOUR;
  1183. }
  1184. }
  1185. if ($CheckReplPeriodStart) {
  1186. if (($rpx < scalar @$LastReplPeriod) && ($Q == $LastReplPeriod->[$rpx])) {
  1187. if (++$Q >= 4*24*7) {$Q = 0;}
  1188. --$intervalExpired;
  1189. ++$i;
  1190. next QTR_HOUR;
  1191. }
  1192. }
  1193. $intervalExpired = $interval; # start of new interval.
  1194. #
  1195. # Mark the duration of the next replication interval.
  1196. #
  1197. if ($rpx >= 0) {
  1198. push @$ReplPeriod, $Q;
  1199. ++$rpx;
  1200. }
  1201. for ($j=0; $j<$duration; $j++) {
  1202. vec($vector, $Q, 1) = 1;
  1203. last if ($Q == $endtime);
  1204. if (++$Q >= 4*24*7) {$Q = 0;}
  1205. --$intervalExpired;
  1206. ++$i;
  1207. }
  1208. #
  1209. # don't advance offset after first replication period is generated.
  1210. #
  1211. $FirstPeriodGen = 1;
  1212. }
  1213. #
  1214. # Consume schedule slots up until the interval between replication
  1215. # periods is >= to the Interval parameter. We may have consumed
  1216. # this interval already if we had to jump past a blackout period.
  1217. #
  1218. if ($intervalExpired > 0) {
  1219. $i += $intervalExpired;
  1220. $Q += $intervalExpired;
  1221. if ($Q >= 4*24*7) {$Q = $Q - 4*24*7;}
  1222. $intervalExpired = 0;
  1223. }
  1224. }
  1225. }
  1226. #
  1227. # Merge in the override setting.
  1228. #
  1229. if (defined $Self->{OVERRIDE}) {
  1230. $vector |= $Self->{OVERRIDE};
  1231. }
  1232. #
  1233. # Apply the timezone shift to the result.
  1234. #
  1235. $tzvector = "";
  1236. vec ($tzvector, 4*24*7-1, 1) = 0;
  1237. for ($i=0; $i<4*24*7; $i++) {
  1238. $Q = $i - $TimeZoneShift;
  1239. if ($Q >= 4*24*7) {
  1240. $Q = $Q - 4*24*7;
  1241. } elsif ($Q < 0) {
  1242. $Q = $Q + 4*24*7;
  1243. }
  1244. vec($tzvector, $Q, 1) = vec($vector, $i, 1);
  1245. }
  1246. #
  1247. # Finally save it as a hex string.
  1248. #
  1249. $Self->{SCHEDULE} = unpack( "h*", $tzvector);
  1250. $Self->Print() if $DEBUG_VERBOSE;
  1251. $Self->{SCHED_DATA_CHANGE} = 0;
  1252. $Self->{REPL_PERIOD_START} = $ReplPeriod;
  1253. }
  1254. sub Print {
  1255. my $Self = shift;
  1256. my $d;
  1257. print "\nFRS_SCHEDULE $Self->{NAME}\n";
  1258. for ($d=0; $d<7; $d++) {
  1259. printf ("%s : %s\n", $NumToDay[$d], substr($Self->{SCHEDULE}, $d*24, 24));
  1260. }
  1261. }
  1262. sub DESTROY {
  1263. my $Self = shift;
  1264. printf("FRS_SCHEDULE $Self->{NAME} dying at %s\n", scalar localtime) if ($DEBUG_OBJ_DEATH);
  1265. }
  1266. package FRS_SERVER;
  1267. use strict;
  1268. #++
  1269. # Package Description:
  1270. # Define state and methods for an FRS server object.
  1271. # This is an internal object used to provide parameters for a
  1272. # member server and to allow the grouping of servers into user defined
  1273. # sets for later processing. For example, the user might create a set
  1274. # of servers that are in a HUB site and another set of servers that
  1275. # correspond to the branch sites.
  1276. #
  1277. # State:
  1278. # UNDER => 'object tag or ref of replica set object',
  1279. # COMPUTER => 'FQDN or Nt4 Acct name (domain\netbiosname$) of computer object',
  1280. # ONAME => 'object name of this object',
  1281. # RP => "root path of replica tree on server",
  1282. # SP => "staging path for this replica set on this server",
  1283. # DNS_NAME => Computer DNS name, e.g. "huba.hubsite.ajax.com");
  1284. # WORKPATH => Working path value for subscriptions object if it is created.
  1285. #
  1286. # Methods:
  1287. #
  1288. #--
  1289. sub New {
  1290. #++
  1291. # Routine Description:
  1292. # Create an FRS_SERVER object.
  1293. #
  1294. # Arguments:
  1295. # ClassName
  1296. # Init args -- see _Init()
  1297. #
  1298. # Return Value:
  1299. # FRS_SERVER object reference
  1300. #
  1301. # Example: FRS_SERVER::New( UNDER=>"RSB", COMPUTER=>"HA", ONAME=>"MEMBER 1" );
  1302. #--
  1303. my $ClassName = shift;
  1304. my $Self = {};
  1305. bless ($Self, $ClassName);
  1306. $Self->_Init(@_);
  1307. return $Self;
  1308. }
  1309. sub _Init {
  1310. #++
  1311. # Routine Description:
  1312. # Init the new FRS_SERVER object.
  1313. #
  1314. # Arguments:
  1315. # Self : Object reference
  1316. # see above.
  1317. #
  1318. # Return Value:
  1319. # void
  1320. #
  1321. #--
  1322. my $Self = shift;
  1323. my ($k, $v);
  1324. print "\nFRS_SERVER:\n" if ($DEBUG_OBJ_CREATE);
  1325. #
  1326. # set private arguments
  1327. #
  1328. $Self->{Test} = 'Test';
  1329. #
  1330. # Set Default arguments
  1331. #
  1332. my %args = (
  1333. RP => '',
  1334. SP => '',
  1335. WORKPATH => '',
  1336. COMPUTER => '',
  1337. DNS_NAME => '',
  1338. @_, # arg pair list
  1339. );
  1340. #
  1341. # set parameter arguments
  1342. #
  1343. if (@_) {
  1344. @$Self{keys %args} = values %args;
  1345. }
  1346. if ($DEBUG_OBJ_CREATE) {
  1347. while ( ($k, $v) = each %$Self ) { print "\t$k => '$v'\n"; }
  1348. }
  1349. # if (wantarray()) {
  1350. # print "list context\n";
  1351. # return; # @many_objs
  1352. # } elsif (defined wantarray()) {
  1353. # print "scalar context\n";
  1354. # return; # $one_obh
  1355. # } else {
  1356. # print "void context\n";
  1357. # return;
  1358. # }
  1359. return;
  1360. }
  1361. sub DESTROY {
  1362. my $Self = shift;
  1363. printf("FRS_SERVER $Self->{DNS_NAME} dying at %s\n", scalar localtime) if ($DEBUG_OBJ_DEATH);
  1364. }
  1365. 1
  1366. __END__