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.
		
		
		
		
		
			
		
			
				
					179 lines
				
				3.8 KiB
			
		
		
			
		
	
	
					179 lines
				
				3.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const childProcess = require('child_process');
							 | 
						||
| 
								 | 
							
								const { isLinux, getReport } = require('./process');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const command = 'getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true';
							 | 
						||
| 
								 | 
							
								let commandOut = '';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const safeCommand = () => {
							 | 
						||
| 
								 | 
							
								  if (!commandOut) {
							 | 
						||
| 
								 | 
							
								    return new Promise((resolve) => {
							 | 
						||
| 
								 | 
							
								      childProcess.exec(command, (err, out) => {
							 | 
						||
| 
								 | 
							
								        commandOut = err ? ' ' : out;
							 | 
						||
| 
								 | 
							
								        resolve(commandOut);
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return commandOut;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const safeCommandSync = () => {
							 | 
						||
| 
								 | 
							
								  if (!commandOut) {
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      commandOut = childProcess.execSync(command, { encoding: 'utf8' });
							 | 
						||
| 
								 | 
							
								    } catch (_err) {
							 | 
						||
| 
								 | 
							
								      commandOut = ' ';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return commandOut;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * A String constant containing the value `glibc`.
							 | 
						||
| 
								 | 
							
								 * @type {string}
							 | 
						||
| 
								 | 
							
								 * @public
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const GLIBC = 'glibc';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * A String constant containing the value `musl`.
							 | 
						||
| 
								 | 
							
								 * @type {string}
							 | 
						||
| 
								 | 
							
								 * @public
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const MUSL = 'musl';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const familyFromReport = () => {
							 | 
						||
| 
								 | 
							
								  const report = getReport();
							 | 
						||
| 
								 | 
							
								  if (report.header && report.header.glibcVersionRuntime) {
							 | 
						||
| 
								 | 
							
								    return GLIBC;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (Array.isArray(report.sharedObjects)) {
							 | 
						||
| 
								 | 
							
								    if (report.sharedObjects.some(isFileMusl)) {
							 | 
						||
| 
								 | 
							
								      return MUSL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const familyFromCommand = (out) => {
							 | 
						||
| 
								 | 
							
								  const [getconf, ldd1] = out.split(/[\r\n]+/);
							 | 
						||
| 
								 | 
							
								  if (getconf && getconf.includes(GLIBC)) {
							 | 
						||
| 
								 | 
							
								    return GLIBC;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (ldd1 && ldd1.includes(MUSL)) {
							 | 
						||
| 
								 | 
							
								    return MUSL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Resolves with the libc family when it can be determined, `null` otherwise.
							 | 
						||
| 
								 | 
							
								 * @returns {Promise<?string>}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const family = async () => {
							 | 
						||
| 
								 | 
							
								  let family = null;
							 | 
						||
| 
								 | 
							
								  if (isLinux()) {
							 | 
						||
| 
								 | 
							
								    family = familyFromReport();
							 | 
						||
| 
								 | 
							
								    if (!family) {
							 | 
						||
| 
								 | 
							
								      const out = await safeCommand();
							 | 
						||
| 
								 | 
							
								      family = familyFromCommand(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return family;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Returns the libc family when it can be determined, `null` otherwise.
							 | 
						||
| 
								 | 
							
								 * @returns {?string}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const familySync = () => {
							 | 
						||
| 
								 | 
							
								  let family = null;
							 | 
						||
| 
								 | 
							
								  if (isLinux()) {
							 | 
						||
| 
								 | 
							
								    family = familyFromReport();
							 | 
						||
| 
								 | 
							
								    if (!family) {
							 | 
						||
| 
								 | 
							
								      const out = safeCommandSync();
							 | 
						||
| 
								 | 
							
								      family = familyFromCommand(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return family;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Resolves `true` only when the platform is Linux and the libc family is not `glibc`.
							 | 
						||
| 
								 | 
							
								 * @returns {Promise<boolean>}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const isNonGlibcLinux = async () => isLinux() && await family() !== GLIBC;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Returns `true` only when the platform is Linux and the libc family is not `glibc`.
							 | 
						||
| 
								 | 
							
								 * @returns {boolean}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const isNonGlibcLinuxSync = () => isLinux() && familySync() !== GLIBC;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const versionFromReport = () => {
							 | 
						||
| 
								 | 
							
								  const report = getReport();
							 | 
						||
| 
								 | 
							
								  if (report.header && report.header.glibcVersionRuntime) {
							 | 
						||
| 
								 | 
							
								    return report.header.glibcVersionRuntime;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const versionSuffix = (s) => s.trim().split(/\s+/)[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const versionFromCommand = (out) => {
							 | 
						||
| 
								 | 
							
								  const [getconf, ldd1, ldd2] = out.split(/[\r\n]+/);
							 | 
						||
| 
								 | 
							
								  if (getconf && getconf.includes(GLIBC)) {
							 | 
						||
| 
								 | 
							
								    return versionSuffix(getconf);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (ldd1 && ldd2 && ldd1.includes(MUSL)) {
							 | 
						||
| 
								 | 
							
								    return versionSuffix(ldd2);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Resolves with the libc version when it can be determined, `null` otherwise.
							 | 
						||
| 
								 | 
							
								 * @returns {Promise<?string>}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const version = async () => {
							 | 
						||
| 
								 | 
							
								  let version = null;
							 | 
						||
| 
								 | 
							
								  if (isLinux()) {
							 | 
						||
| 
								 | 
							
								    version = versionFromReport();
							 | 
						||
| 
								 | 
							
								    if (!version) {
							 | 
						||
| 
								 | 
							
								      const out = await safeCommand();
							 | 
						||
| 
								 | 
							
								      version = versionFromCommand(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return version;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Returns the libc version when it can be determined, `null` otherwise.
							 | 
						||
| 
								 | 
							
								 * @returns {?string}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const versionSync = () => {
							 | 
						||
| 
								 | 
							
								  let version = null;
							 | 
						||
| 
								 | 
							
								  if (isLinux()) {
							 | 
						||
| 
								 | 
							
								    version = versionFromReport();
							 | 
						||
| 
								 | 
							
								    if (!version) {
							 | 
						||
| 
								 | 
							
								      const out = safeCommandSync();
							 | 
						||
| 
								 | 
							
								      version = versionFromCommand(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return version;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = {
							 | 
						||
| 
								 | 
							
								  GLIBC,
							 | 
						||
| 
								 | 
							
								  MUSL,
							 | 
						||
| 
								 | 
							
								  family,
							 | 
						||
| 
								 | 
							
								  familySync,
							 | 
						||
| 
								 | 
							
								  isNonGlibcLinux,
							 | 
						||
| 
								 | 
							
								  isNonGlibcLinuxSync,
							 | 
						||
| 
								 | 
							
								  version,
							 | 
						||
| 
								 | 
							
								  versionSync
							 | 
						||
| 
								 | 
							
								};
							 |