Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat special chars and more #3728

Merged
merged 14 commits into from
Feb 20, 2024
3 changes: 2 additions & 1 deletion bin/libs/configmgr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as os from 'cm_os';
import * as xplatform from 'xplatform';
import { ConfigManager } from 'Configuration';
import * as fs from './fs';
import * as stringlib from './string';

import * as objUtils from '../utils/ObjUtils';

Expand Down Expand Up @@ -415,7 +416,7 @@ function getMemberNameFromConfigPath(configPath: string): string|undefined {
function stripMemberName(configPath: string, memberName: string): string {
//Turn PARMLIB(my.zowe(yaml)):PARMLIB(my.other.zowe(yaml))
//Into PARMLIB(my.zowe):FILE(/some/path.yaml):PARMLIB(my.other.zowe)
const replacer = new RegExp('\\('+memberName+'\\)\\)', 'gi');
const replacer = new RegExp('\\('+stringlib.escapeDollar(memberName)+'\\)\\)', 'gi');
return configPath.replace(replacer, ")");
}

Expand Down
13 changes: 13 additions & 0 deletions bin/libs/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,16 @@ export function itemInList(stringList: string, stringToFind?: string, separator:
}
return stringList.split(separator).includes(stringToFind);
}

export function escapeDollar(str: string): string | undefined {
if (str === null || str === undefined)
return undefined;
return str.replace(/[$]/g, '\\$&');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain what the ampersand '&' does here?
I'm not familiar with it and a quick search didnt tell me why it is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explanation here.

$& = inserts the matched substring.

It is better to show on the second replacement:
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');: any character from [] found, replace by backslash and that character.

The first replace is just for one char, but the replacement is in general form. It can be changed to str.replace(/[$]/g, '\\$'); if it makes the code better to read. This or that, it will work the same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay now i understand. i thought $& was a shell thing, i didn't realize it was a javascript thing.

}

export function escapeRegExp(str: string): string | undefined {
if (str === null || str === undefined)
return undefined;
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

27 changes: 13 additions & 14 deletions bin/libs/zos-dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as shell from './shell';
import * as zoslib from './zos';

export function isDatasetExists(datasetName: string): boolean {
const result = shell.execSync('sh', '-c', `cat "//'${datasetName}'" 1>/dev/null 2>&1`);
const result = shell.execSync('sh', '-c', `cat "//'${stringlib.escapeDollar(datasetName)}'" 1>/dev/null 2>&1`);
return result.rc === 0;
}

Expand All @@ -27,7 +27,7 @@ export function isDatasetExists(datasetName: string): boolean {
// 1: data set is not in catalog
// 2: data set member doesn't exist
export function tsoIsDatasetExists(datasetName: string): number {
const result = zoslib.tsoCommand(`listds '${datasetName}' label`);
const result = zoslib.tsoCommand(`listds '${stringlib.escapeDollar(datasetName)}' label`);
if (result.rc != 0) {
if (result.out.includes('NOT IN CATALOG')) {
return 1;
Expand All @@ -44,7 +44,7 @@ export function tsoIsDatasetExists(datasetName: string): number {
}

export function createDataSet(dsName: string, dsOptions: string): number {
const result=zoslib.tsoCommand(`ALLOCATE NEW DA('${dsName}') ${dsOptions}`);
const result=zoslib.tsoCommand(`ALLOCATE NEW DA('${stringlib.escapeDollar(dsName)}') ${dsOptions}`);
return result.rc;
}

Expand All @@ -55,7 +55,7 @@ export function copyToDataset(filePath: string, dsName: string, cpOptions: strin
}
}

const cpCommand=`cp ${cpOptions} -v "${filePath}" "//'${dsName}'"`;
const cpCommand=`cp ${cpOptions} -v "${filePath}" "//'${stringlib.escapeDollar(dsName)}'"`;
common.printDebug('- '+cpCommand);
const result=shell.execOutSync('sh', '-c', `${cpCommand} 2>&1`);
if (result.rc == 0) {
Expand All @@ -79,7 +79,7 @@ export function datasetCopyToDataset(prefix: string, datasetFrom: string, datase
}
}

const cmd=`exec '${prefix}.${std.getenv('ZWE_PRIVATE_DS_SZWEEXEC')}(ZWEMCOPY)' '${datasetFrom} ${datasetTo}'`;
const cmd = `exec '${stringlib.escapeDollar(prefix)}.${std.getenv('ZWE_PRIVATE_DS_SZWEEXEC')}(ZWEMCOPY)' '${stringlib.escapeDollar(datasetFrom)} ${stringlib.escapeDollar(datasetTo)}'`;
const result = zoslib.tsoCommand(cmd);
return result.rc;
}
Expand All @@ -91,7 +91,7 @@ export function datasetCopyToDataset(prefix: string, datasetFrom: string, datase
// 1: there are some users
// @output output of operator command "d grs"
export function listDatasetUser(datasetName: string): number {
const cmd=`D GRS,RES=(*,${datasetName})`;
const cmd = `D GRS,RES=(*,'${stringlib.escapeDollar(datasetName)}')`;
const result=zoslib.operatorCommand(cmd);
return result.out.includes('NO REQUESTORS FOR RESOURCE') ? 0 : 1;
// example outputs:
Expand Down Expand Up @@ -128,7 +128,7 @@ export function listDatasetUser(datasetName: string): number {
// 3: data set is in use
// @output tso listds label output
export function deleteDataset(dataset: string): number {
const cmd=`delete '${dataset}'`;
const cmd=`delete '${stringlib.escapeDollar(dataset)}'`;
const result=zoslib.tsoCommand(cmd);
if (result.rc != 0) {
if (result.out.includes('NOT IN CATALOG')) {
Expand Down Expand Up @@ -170,7 +170,7 @@ export function isDatasetSmsManaged(dataset: string): { rc: number, smsManaged?:
// SMS flag is in `FORMAT 1 DSCB` section second line, after 780037

common.printTrace(`- Check if ${dataset} is SMS managed`);
const labelResult = zoslib.tsoCommand(`listds '${dataset}' label`);
const labelResult = zoslib.tsoCommand(`listds '${stringlib.escapeDollar(dataset)}' label`);
const datasetLabel=labelResult.out;
if (labelResult.rc == 0) {
let formatIndex = datasetLabel.indexOf('--FORMAT 1 DSCB--');
Expand Down Expand Up @@ -212,14 +212,13 @@ export function isDatasetSmsManaged(dataset: string): { rc: number, smsManaged?:

export function getDatasetVolume(dataset: string): { rc: number, volume?: string } {
common.printTrace(`- Find volume of data set ${dataset}`);
const result = zoslib.tsoCommand(`listds '${dataset}'`);
const result = zoslib.tsoCommand(`listds '${stringlib.escapeDollar(dataset)}'`);
if (result.rc == 0) {
let volumesIndex = result.out.indexOf('--VOLUMES--');
let volume: string;
if (volumesIndex != -1) {
let startIndex = volumesIndex + '--VOLUMES--'.length;
let endIndex = result.out.indexOf('--',startIndex);
volume = result.out.substring(startIndex, endIndex).trim();
volume = result.out.substring(startIndex).trim();
}
if (!volume) {
common.printError(" * Failed to find volume information of the data set.");
Expand All @@ -235,7 +234,7 @@ export function getDatasetVolume(dataset: string): { rc: number, volume?: string
export function apfAuthorizeDataset(dataset: string): number {
const result = isDatasetSmsManaged(dataset);
if (result.rc) {
common.printError("Error ZWEL0134E: Failed to find SMS status of data set ${dataset}.");
common.printError(`Error ZWEL0134E: Failed to find SMS status of data set ${dataset}.`);
return 134;
}

Expand All @@ -256,7 +255,7 @@ export function apfAuthorizeDataset(dataset: string): number {
}
}

const apfCmd="SETPROG APF,ADD,DSNAME=${dataset},${apfVolumeParam}"
const apfCmd=`SETPROG APF,ADD,DSNAME=${dataset},${apfVolumeParam}`;
if (std.getenv('ZWE_CLI_PARAMETER_SECURITY_DRY_RUN') == "true") {
common.printMessage("- Dry-run mode, security setup is NOT performed on the system.");
common.printMessage(" Please apply this operator command manually:");
Expand All @@ -277,7 +276,7 @@ export function apfAuthorizeDataset(dataset: string): number {
}

export function createDatasetTmpMember(dataset: string, prefix: string='ZW'): string | null {
common.printTrace(` > create_data_set_tmp_member in ${dataset}`);
common.printTrace(` > createDatasetTmpMember in ${dataset}`);
for (var i = 0; i < 100; i++) {
let rnd=Math.floor(Math.random()*10000);

Expand Down
4 changes: 2 additions & 2 deletions bin/libs/zos-fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function detectFileEncoding(fileName: string, expectedSample: string, exp

export function copyMvsToUss(dataset: string, file: string): number {
common.printDebug(`copyMvsToUss dataset=${dataset}, file=${file}`);
const result = shell.execSync('sh', '-c', `cp "//'${dataset}'" "${file}"`);
const result = shell.execSync('sh', '-c', `cp "//'${stringlib.escapeDollar(dataset)}'" '${file}'`);
return result.rc;
}

Expand All @@ -111,7 +111,7 @@ export function ensureFileEncoding(file: string, expectedSample: string, expecte
}
}
common.printTrace(`- Remove encoding tag of ${file}.`);
zos.changeTag(file, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this cause any change in zwe performance?

shell.execSync('sh', '-c', `chtag -r "${file}"`);
} else {
common.printTrace(`- Failed to detect encoding of ${file}.`);
}
Expand Down
2 changes: 1 addition & 1 deletion bin/libs/zos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import * as shell from './shell';
import * as stringlib from './string';

export function tsoCommand(...args:string[]): { rc: number, out: string } {
let message="tsocmd "+args.join(' ');
let message = "tsocmd " + '"' + args.join(' ') + '"';
common.printDebug('- '+message);
//we echo at the end to avoid a configmgr quirk where trying to read stdout when empty can hang waiting for bytes
const result = shell.execOutSync('sh', '-c', `${message} 2>&1 && echo '.'`);
Expand Down
3 changes: 3 additions & 0 deletions bin/libs/zwecli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ zwecli_inline_execute_command() {

export ZWE_PRIVATE_CLI_IS_TOP_LEVEL_COMMAND=false

print_trace "- zwecli_inline_execute_command"
print_trace " * ${*}"

# process new command
. "${ZWE_zowe_runtimeDirectory}/bin/zwe"

Expand Down
Loading