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.

464 lines
20 KiB

  1. @rem = '
  2. @goto endofperl
  3. ';
  4. # TODO:
  5. # ADD $retrysleep $retrycount
  6. # Allow /verbose /debug /dc to come from cmd line.
  7. # test /autoclean
  8. # Add /DELRS [rsname | *]
  9. # - This reads all the MKDS* cmds from the infile then it deletes
  10. # all the cxtions under each member for the specified replica
  11. # set name (or all replica sets in the infile if *). Then it
  12. # deletes all member & subscriber objects and then deletes
  13. # the replica set object(s).
  14. # Add /DELCONN [rsname | *]
  15. # - This reads all the MKDS* cmds from the infile then it deletes
  16. # all the cxtions under each member for the specified replica
  17. # set name (or all cxtions under all members for all replica
  18. # sets in the infile if *).
  19. #
  20. $USAGE = "
  21. Usage: $0 InputFiles
  22. FRSConfig takes the output from mkrepset and creates the appropriate
  23. objects in the DS. The input file contains commands to invoke mkdsxe.exe and
  24. mkdsoe.exe which actually create the objects in the DS using ldap calls.
  25. FRSConfig parameters set via enviroment vars.
  26. MKDSX_REDO_FILE Output file of failed mkdsx commands (default: MKDSX.REDO)
  27. MKDSX_DCNAME computer name of DC to bind to.
  28. FRSConfig paramters set via input file command lines. They can not be set
  29. on the command line invoking FRSConfig.
  30. /dc <default computer name of DC on which to create the objects>
  31. not avail --- /auto_cleanup [DCname1 DCname2 ...]
  32. /debug processes the file but prevents any modification to the DC.
  33. /verbose enables verbose output.
  34. No embedded blanks are allowed within parameters.
  35. The /dc option can be used in two ways:
  36. 1. On a command line by itself to specify the global default DC on which
  37. to create/update the connection object for subsequent connection operation
  38. commands. The default can be changed multiple times in the input file.
  39. 2. The /dc option can also be used at the end of the create, update, del
  40. and dump commands to override the current global default for this
  41. single command. This is useful if you need to create a connection object
  42. on a remote DC that currently has no connection objects and so is not
  43. replicating but the global default is sufficient for all the other commands.
  44. [/auto_cleanup not avail]
  45. The /auto_cleanup option is used to automatically delete ALL old connections
  46. under a given host site\\server before the first new connection is created.
  47. This is done only once before the first create operation on the host is processed.
  48. If the first operation on a given host is an update command then it is assumed
  49. that no cleanup should be done on this host. The del and dump commands do not
  50. trigger an auto cleanup. The actual delete connection operation is performed on the
  51. DC specified by the /dc option described above. In addition the /auto_cleanup
  52. option can take an optional list of DC computer names separated by spaces.
  53. If supplied, the automatic connection delete operation is ALSO performed on EACH
  54. of these DCs. This is useful if you are creating new inbound connection
  55. objects on branch DCs and want to be sure that any old inbound connection
  56. objects are deleted on the branch DC AND on the Hub DCs. Otherwise if the
  57. branch has not replicated in some time there could be undesired connection
  58. objects lingering on the Hub DC that will replicate to the branch once the new
  59. connection object is created. You can prevent this by specifying a list of Hub
  60. DC names as parameters to the /auto_cleanup option.
  61. Comment lines can be prefixed by \"#\" or \"REM\".
  62. SAMPLE INPUT FILE ---
  63. # A sample input file to create one replica set with three members and the
  64. # associated connections might look as follows:
  65. #
  66. /dc ntdev-dc-01
  67. mkdsoe /createset /ntfrssettingsdn 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /setname 'WD-test4' /settype 3 /filefilter '~*,*.tmp,*.bak'
  68. mkdsoe /createmember /NtfrsSettingsDN 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /SetName 'WD-test4' /ComputerName 'frs1221\test1$' /MemberName 'Primary Hub'
  69. mkdsoe /createsubscriber /NtfrsSettingsDN 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /SetName 'WD-test4' /ComputerName 'frs1221\test1$' /MemberName 'Primary Hub' /RootPath 'E:\RSB-test4' /StagePath 'D:\staging'
  70. mkdsoe /createmember /NtfrsSettingsDN 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /SetName 'WD-test4' /ComputerName 'frs1221\test2$' /MemberName 'Backup Hub'
  71. mkdsoe /createsubscriber /NtfrsSettingsDN 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /SetName 'WD-test4' /ComputerName 'frs1221\test2$' /MemberName 'Backup Hub' /RootPath 'E:\RSB-test4' /StagePath 'D:\staging'
  72. mkdsoe /createmember /NtfrsSettingsDN 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /SetName 'WD-test4' /ComputerName 'frs1221\test4$' /MemberName 'Branch'
  73. mkdsoe /createsubscriber /NtfrsSettingsDN 'cn=ntfrs test settings,cn=services,cn=configuration,dc=frs1221,dc=nttest,dc=microsoft,dc=com' /SetName 'WD-test4' /ComputerName 'frs1221\test4$' /MemberName 'Branch' /RootPath 'D:\RSB' /StagePath 'D:\staging'
  74. #
  75. # Create the connections
  76. #
  77. mkdsxe.exe /create /DC TEST1 /ReplicaSetName 'WD-test4' /Name 'FROM-PRIMARY-HUB' /ToComputer 'test4.frs1221.nttest.microsoft.com' /FromComputer 'test1.frs1221.nttest.microsoft.com' /Schedule 16 8 0 /enable
  78. mkdsxe.exe /create /ReplicaSetName 'WD-test4' /Name 'FROM-BACKUP-HUB' /ToComputer 'test4.frs1221.nttest.microsoft.com' /FromComputer 'test2.frs1221.nttest.microsoft.com' /Schedule 16 8 8 /enable
  79. mkdsxe.exe /create /ReplicaSetName 'WD-test4' /Name 'FROM-BRANCH-PRIMARY' /ToComputer 'test1.frs1221.nttest.microsoft.com' /FromComputer 'test4.frs1221.nttest.microsoft.com' /Schedule 16 8 0 /enable
  80. mkdsxe.exe /create /ReplicaSetName 'WD-test4' /Name 'FROM-BRANCH-BACKUP' /ToComputer 'test2.frs1221.nttest.microsoft.com' /FromComputer 'test4.frs1221.nttest.microsoft.com' /Schedule 16 8 8 /enable
  81. mkdsxe.exe /create /ReplicaSetName 'WD-test4' /Name 'INTER-HUB1' /ToComputer 'test1.frs1221.nttest.microsoft.com' /FromComputer 'test2.frs1221.nttest.microsoft.com' /enable
  82. mkdsxe.exe /create /ReplicaSetName 'WD-test4' /Name 'INTER-HUB2' /ToComputer 'test2.frs1221.nttest.microsoft.com' /FromComputer 'test1.frs1221.nttest.microsoft.com' /enable
  83. #End of file
  84. ERROR HANDLING --
  85. Any command line that returns an error is written to the ReDo file.
  86. An error message is written to standard out.
  87. Note: The redo file is deleted when the script starts so if no redo file exists
  88. after completion of the script then all commands were processed without errors.
  89. ";
  90. die $USAGE unless @ARGV;
  91. $mkdsx = "mkdsxe.exe ";
  92. $varnumargs = 99;
  93. $time = scalar localtime;
  94. printf DAT ("Running FRSConfig on: %s\n", $time);
  95. printf("\n\n");
  96. $redo = $ENV{'MKDSX_REDO_FILE'}; printf("MKDSX_REDO_FILE: %s\n", $redo);
  97. $dcname = $ENV{'MKDSX_DCNAME'}; printf("MKDSX_DCNAME: %s\n", $dcname);
  98. $verbose = $ENV{'MKDSX_VERBOSE'}; printf("MKDSX_VERBOSE: %s\n", $verbose);
  99. if ($redo eq "") {$redo = "install.redo";}
  100. if ($dcname ne "") {$dcname = " /dc $dcname";}
  101. if ($verbose ne "") {$verbosemode = "/v";}
  102. printf("\n\n");
  103. print $0 @argv;
  104. printf("Redo File: %s\n", $redo) if ($redo ne "");
  105. #
  106. # mkdsxe.exe error return codes (from mkdsx.h)
  107. #
  108. %ErrMsg = (
  109. 0 => { ErrCode => MKDSXE_SUCCESS , Text => "MKDSXE Success."},
  110. 1 => { ErrCode => MKDSXE_BAD_ARG , Text => "Invalid Arguments."},
  111. 2 => { ErrCode => MKDSXE_CANT_BIND , Text => "Could not bind to the DC."},
  112. 3 => { ErrCode => MKDSXE_NO_T0_NTDS_SETTINGS , Text => "Could not find 'NTDS Settings' object. Check the host site\\server parameter."},
  113. 4 => { ErrCode => MKDSXE_NO_FROM_NTDS_SETTINGS , Text => "Could not find 'NTDS Settings' object. Check the from site\\server parameter."},
  114. 5 => { ErrCode => MKDSXE_CXTION_OBJ_CRE_FAILED , Text => "Error creating connection."},
  115. 6 => { ErrCode => MKDSXE_UNUSED_1 , Text => "Connection already exists."},
  116. 7 => { ErrCode => MKDSXE_CXTION_OBJ_UPDATE_FAILED, Text => "Error updating connection."},
  117. 8 => { ErrCode => MKDSXE_CXTION_NOT_FOUND_UPDATE , Text => "Error updating connection}, connection not found."},
  118. 9 => { ErrCode => MKDSXE_CXTION_DUPS_FOUND_UPDATE, Text => "Error updating connection}, duplicate connections found."},
  119. 10 => { ErrCode => MKDSXE_CXTION_DELETE_FAILED , Text => "Error deleting connection."},
  120. 11 => { ErrCode => MKDSXE_CXTION_NOT_FOUND_DELETE , Text => "Error deleting connection}, connection not found."},
  121. 12 => { ErrCode => MKDSXE_MULTIPLE_CXTIONS_DELETED, Text => "Deleting multiple connection."},
  122. 13 => { ErrCode => MKDSXE_CXTION_DUMP_FAILED , Text => "Error dumping connection."},
  123. 14 => { ErrCode => MKDSXE_CXTION_NOT_FOUND_DUMP , Text => "Error dumping}, connection not found."},
  124. 15 => { ErrCode => MKDSXE_MULTIPLE_CXTIONS_DUMPED , Text => "Dumping duplicate connections."},
  125. #
  126. # mkdsoe.exe error return codes (from mkdso.h)
  127. #
  128. 100 => { ErrCode => MKDSOE_SUCCESS , Text => "MKDSOE Success."},
  129. 101 => { ErrCode => MKDSOE_BAD_ARG , Text => "Invalid Arguments."},
  130. 102 => { ErrCode => MKDSOE_CANT_BIND , Text => "Could not bind to the DC."},
  131. 103 => { ErrCode => MKDSOE_NO_NTFRS_SETTINGS , Text => "Could not find 'NTFRS Settings' object. Check the /settingsdn parameter."},
  132. 104 => { ErrCode => MKDSOE_SET_OBJ_CRE_FAILED , Text => "Error creating replica set."},
  133. 105 => { ErrCode => MKDSOE_SET_OBJ_UPDATE_FAILED , Text => "Error updating replica set."},
  134. 106 => { ErrCode => MKDSOE_SET_NOT_FOUND_UPDATE , Text => "Error updating replica set}, set not found."},
  135. 107 => { ErrCode => MKDSOE_SET_DUPS_FOUND_UPDATE , Text => "Error updating replica set}, duplicate sets found."},
  136. 108 => { ErrCode => MKDSOE_SET_DUPS_FOUND_DELETE , Text => "Error deleting replica set}, duplicate sets found."},
  137. 109 => { ErrCode => MKDSOE_SET_DELETE_FAILED , Text => "Error deleting replica set."},
  138. 110 => { ErrCode => MKDSOE_SET_NOT_FOUND_DELETE , Text => "Error deleting replica set}, set not found."},
  139. 111 => { ErrCode => MKDSOE_MULTIPLE_SETS_DELETED , Text => "Deleting multiple sets."},
  140. 112 => { ErrCode => MKDSOE_SET_DUMP_FAILED , Text => "Error dumping replica set."},
  141. 113 => { ErrCode => MKDSOE_SET_NOT_FOUND_DUMP , Text => "Error dumping replica set}, set not found."},
  142. 114 => { ErrCode => MKDSOE_MULTIPLE_SETS_DUMPED , Text => "Dumping duplicate sets."},
  143. 115 => { ErrCode => MKDSOE_MEMBER_OBJ_CRE_FAILED , Text => "Error creating replica member."},
  144. 116 => { ErrCode => MKDSOE_MEMBER_OBJ_UPDATE_FAILED , Text => "Error updating replica member."},
  145. 117 => { ErrCode => MKDSOE_MEMBER_NOT_FOUND_UPDATE , Text => "Error updating replica member}, member not found."},
  146. 118 => { ErrCode => MKDSOE_MEMBER_DUPS_FOUND_UPDATE , Text => "Error updating replica member}, duplicate members found."},
  147. 119 => { ErrCode => MKDSOE_MEMBER_DUPS_FOUND_DELETE , Text => "Error deleting member}, duplicate subscribers found."},
  148. 120 => { ErrCode => MKDSOE_MEMBER_DELETE_FAILED , Text => "Error deleting replica member."},
  149. 121 => { ErrCode => MKDSOE_MEMBER_NOT_FOUND_DELETE , Text => "Error deleting replica member}, member not found."},
  150. 122 => { ErrCode => MKDSOE_MULTIPLE_MEMBERS_DELETED , Text => "Deleting multiple members."},
  151. 123 => { ErrCode => MKDSOE_MEMBER_DUMP_FAILED , Text => "Error dumping replica member."},
  152. 124 => { ErrCode => MKDSOE_MEMBER_NOT_FOUND_DUMP , Text => "Error dumping replica member}, member not found."},
  153. 125 => { ErrCode => MKDSOE_MULTIPLE_MEMBERS_DUMPED , Text => "Dumping duplicate members."},
  154. 126 => { ErrCode => MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED , Text => "Error creating subscriber."},
  155. 127 => { ErrCode => MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED , Text => "Error updating subscriber."},
  156. 128 => { ErrCode => MKDSOE_SUBSCRIBER_NOT_FOUND_UPDATE , Text => "Error updating subscriber}, subscriber not found."},
  157. 129 => { ErrCode => MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE , Text => "Error updating subscriber}, duplicate subscribers found."},
  158. 130 => { ErrCode => MKDSOE_SUBSCRIBER_DELETE_FAILED , Text => "Error deleting subscriber."},
  159. 131 => { ErrCode => MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE , Text => "Error deleting subscriber}, subscriber not found."},
  160. 132 => { ErrCode => MKDSOE_MULTIPLE_SUBSCRIBERS_DELETE , Text => "Deleting multiple subscribers."},
  161. 133 => { ErrCode => MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE , Text => "Error deleting subscriber}, duplicate subscribers found."},
  162. 134 => { ErrCode => MKDSOE_SUBSCRIBER_DUMP_FAILED , Text => "Error dumping subscriber."},
  163. 135 => { ErrCode => MKDSOE_SUBSCRIBER_NOT_FOUND_DUMP , Text => "Error dumping subscriber}, subscriber not found."},
  164. 136 => { ErrCode => MKDSOE_MULTIPLE_SUBSCRIBERS_DUMPED , Text => "Dumping duplicate subscribers."},
  165. );
  166. #
  167. # Valid commands with number of required params.
  168. #
  169. $linenumber = 0;
  170. $InFile = "";
  171. unlink $redo;
  172. $redo_cnt = 0;
  173. $cleanup = 0;
  174. while (<>) {
  175. if ($InFile ne $ARGV) {
  176. $InFile = $ARGV;
  177. printf("Processing file %s \n\n", $InFile);
  178. $linenumber = 0;
  179. }
  180. $linenumber++;
  181. $cleancmd = "";
  182. chop;
  183. ($func, @a) = split;
  184. if (($func eq "") || ($func =~ m/^#|^REM/i)) {next;}
  185. #
  186. # check for valid command. Skip it quietly since user prints could be present.
  187. #
  188. if (!($func =~ m/^mkdsxe | ^mkdsoe | ^\/dc | ^\/debug | ^\/verbose/xi)) {
  189. #printf("Line %d: Error: %s unrecognized command.\n%s\n\n", $linenumber, $func, $_);
  190. #goto ERROR;
  191. next;
  192. }
  193. if ($func =~ m/\/dc/i) {
  194. $dcname = " /dc $a[0]";
  195. printf("Default DC name change: %s\n", $a[0]);
  196. next;
  197. }
  198. if ($func =~ m/\/debug/i) {
  199. printf("Debug mode enabled. DC modifications supressed.\n");
  200. $debugmode = "/debug";
  201. next;
  202. }
  203. if ($func =~ m/\/verbose/i) {
  204. printf("Verbose mode enabled.\n");
  205. $verbosemode = "/v";
  206. next;
  207. }
  208. #
  209. # check for explicit DC on command.
  210. #
  211. $binddc = (m/\s* \/dc \s*/ix) ? "" : $dcname;
  212. #
  213. # build function call for create / update commands.
  214. #
  215. if (m/\/create | \/update/ix) {
  216. #
  217. # Make up a delete command if we are auto cleaning old connections.
  218. #
  219. # if ($cleanup && (m/\/create/i) && !$hostcleaned{$host}) {
  220. # $cleancmd = "$mkdsx $debugmode $verbosemode \
  221. # /del /tosite $host_site /toserver $host_srv /all";
  222. # }
  223. #
  224. # Remember that we have done either a create or update against this
  225. # host site\server so it is done only once. In particular if we
  226. # see an update command for a host before the first create for the host
  227. # we will NOT do a cleanup on that host if we see a create for it later.
  228. #
  229. # $hostcleaned{$host} += 1;
  230. }
  231. #
  232. # build the command with verbose, debug and binddc options.
  233. #
  234. $mcmd = $_ . $binddc;
  235. $mcmd =~ s/\s+/ $verbosemode $debugmode /;
  236. #
  237. # Do the operation on the connection.
  238. #
  239. if ($verbosemode ne "" ) {printf("\n");}
  240. printf("%s\n", $_);
  241. # if ($cleancmd ne "") {
  242. # doautoclean($cleancmd);
  243. # }
  244. $save_cmd = $_;
  245. if ($verbosemode ne "" ) {printf("\nRunning:\n%s\n", $mcmd)};
  246. #
  247. # Run the command and capture the output so we can merge it correctly with
  248. # the output stream of this script.
  249. #
  250. open(README, "$mcmd |") or die "Can't run program: $!\n";
  251. while(<README>) {
  252. print $_;
  253. }
  254. close(README);
  255. $rc = $? / 256;
  256. if (($ErrMsg{$rc}{ErrCode} ne MKDSXE_SUCCESS) &&
  257. ($ErrMsg{$rc}{ErrCode} ne MKDSOE_SUCCESS)) {
  258. printf("Line %d: Error from $func (%d) - %s, %s - skipping\n%s\n\n",
  259. $linenumber, $rc, $ErrMsg{$rc}{ErrCode}, $ErrMsg{$rc}{Text}, $save_cmd);
  260. ++$redo_cnt;
  261. goto REDO_CMD;
  262. }
  263. next;
  264. ERROR:
  265. #
  266. # append command record to redo file.
  267. #
  268. $errorcount += 1;
  269. REDO_CMD:
  270. open(REDO, ">>$redo");
  271. #
  272. # put options out first.
  273. #
  274. if ($redo_cnt == 1) {
  275. $time = scalar localtime;
  276. printf REDO ("#Time generated: %s\n", $time);
  277. print REDO "$dcname \n";
  278. print REDO "/auto_cleanup ", @cleanup_list if ($cleanup == 1);
  279. print REDO "/debug \n" if ($debugmode ne "");
  280. print REDO "/verbose \n" if ($verbosemode ne "");
  281. print REDO "# \n";
  282. }
  283. print REDO $save_cmd, "\n";
  284. close(REDO);
  285. } # end while()
  286. printf("WARNING: %d command(s) were not performed. They were written to the Redo File: %s\n",
  287. $errorcount, $redo) if ($errorcount > 0);
  288. printf("WARNING: %d command(s) failed their connection operation. They were written to the Redo File: %s\n",
  289. $redo_cnt, $redo) if ($redo_cnt > 0);
  290. sub doautoclean {
  291. ######### Not tested for FRS replica sets.
  292. #++
  293. #
  294. # Routine Description:
  295. #
  296. # Run the cleanup command to delete old connections for this site\server.
  297. # This is executed on the target DC.
  298. # If the optional auto cleanup list is supplied then run the command
  299. # against each DC in the list.
  300. #
  301. # If the global params $retrycount and $retrysleep are provided then
  302. # the command is retried after a sleep period if the return status from
  303. # mkdsx is $MKDSXE_CANT_BIND. This is to handle the case where a dialup
  304. # connection is takes too long to be established so the ldap_bind fails.
  305. #
  306. # Arguments:
  307. #
  308. # $command -- The mkdsx connection delete command.
  309. #
  310. # Return Value:
  311. #
  312. # None
  313. #
  314. #--
  315. my ($rclast, $retryx, $rc, $targetdc);
  316. my($command) = @_;
  317. printf("\nRunning autoclean:\n%s\n", $command) if ($verbosemode ne "");
  318. printf(" Clean - %s\n", $binddc) if ($verbosemode ne "");
  319. $rclast = -1;
  320. $retryx = $retrycount;
  321. while ($retryx-- > 0) {
  322. $rc = system ("$command $binddc") / 256;
  323. last if (($ErrMsg{$rc}{ErrCode} eq MKDSXE_SUCCESS) ||
  324. ($ErrMsg{$rc}{ErrCode} eq MKDSOE_SUCCESS));
  325. if ((($ErrMsg{$rc}{ErrCode} ne MKDSXE_SUCCESS) &&
  326. ($ErrMsg{$rc}{ErrCode} ne MKDSOE_SUCCESS)) &&
  327. ($rc != $rclast)) {
  328. printf("Line %d: Status return from mkdsx.exe (%d) - %s, %s - for auto cleanup command. Continuing.\n",
  329. $linenumber, $rc, $ErrMsg{$rc}{ErrCode}, $ErrMsg{$rc}{Text});
  330. $rclast = $rc;
  331. }
  332. last if ($ErrMsg{$rc}{ErrCode} ne MKDSXE_CANT_BIND) &&
  333. ($ErrMsg{$rc}{ErrCode} ne MKDSOE_CANT_BIND);
  334. printf("Line %d: Sleep %d sec followed by a retry\n", $linenumber, $retrysleep);
  335. sleep $retrysleep;
  336. }
  337. #
  338. # Do the same to the auto cleanup list if we have one.
  339. #
  340. foreach $targetdc (@cleanup_list) {
  341. printf(" Clean - /dc %s\n", $targetdc) if ($verbosemode ne "");
  342. $rclast = -1;
  343. $retryx = $retrycount;
  344. while ($retryx-- > 0) {
  345. $rc = system ("$cleancmd /dc $targetdc") / 256;
  346. last if (($ErrMsg{$rc}{ErrCode} eq MKDSXE_SUCCESS) ||
  347. ($ErrMsg{$rc}{ErrCode} eq MKDSOE_SUCCESS));
  348. if ((($ErrMsg{$rc}{ErrCode} ne MKDSXE_SUCCESS) &&
  349. ($ErrMsg{$rc}{ErrCode} ne MKDSOE_SUCCESS)) &&
  350. ($rc != $rclast)) {
  351. printf("Line %d: Status return from mkdsx.exe (%d) - %s, %s - for auto cleanup command. Continuing.\n",
  352. $linenumber, $rc, $ErrMsg{$rc}{ErrCode}, $ErrMsg{$rc}{Text});
  353. }
  354. last if ($ErrMsg{$rc}{ErrCode} ne MKDSXE_CANT_BIND) &&
  355. ($ErrMsg{$rc}{ErrCode} ne MKDSOE_CANT_BIND);
  356. printf("Line %d: Sleep %d sec followed by a retry\n", $linenumber, $retrysleep);
  357. sleep $retrysleep;
  358. }
  359. }
  360. }
  361. __END__
  362. :endofperl
  363. @perl %~dpn0.cmd %*