LINUX.ORG.RU

Один бинарник на четыре системы

 , , , ,


8

1

Это текстовая версия статьи, оригинал с картинками вот тут

Все что мы делаем — отражается эхом в вечности, надеюсь что меня запомнят по этой работе, ибо творил я во славу ультрахардкора.

This is Spartaaa!

Обычные программы либо компилируются под какую-то конкретную ОС и архитектуру процессора, либо же требуют специальное окружение для запуска и работы. Которое еще нужно скачать и установить.

Это — норма и для коммерческого софта лучше так и делать впредь. Хоть это и серо, скучно и уныло.

То что я покажу ниже в этой статье — «Proof of Concept» (PoC), доказательство что сделать единый запускаемый бинарник под четыре абсолютно разные и несовместимые платформы технически возможно.

Как это выглядит

Один исполняемый файл all.cmd без изменений, без перекомпиляции и сборок запускается «as-is» на Windows, Linux, FreeBSD и MacOS. Запускается именно в пользовательском смысле: по клику, по нажатию Enter, через ./all.cmd — так как запускается обычная родная программа в каждой конкретной ОС. Без дополнительных действий, без каких-то параметров запуска, без всего. Вообщем, по хардкору.

Как это работает

Шелл-скрипт упаковывается вместе с бинарником в один файл. Скрипт — в начале файла, бинарник с приложением — в конце. Сама по себе технология известная. но у меня получилось развить ее несколько дальше:

Я использовал приложение на Java в качестве бинарника, но тоже самое можно реализовать и с дотнетом и с Python-приложением.

Jar файл, в который упаковывается Java-приложение является ZIP-архивом, особенностью формата которого является то, что процесс чтения начинается с конца файла.

А вот шелл-скрипт как и Windows Batch выполняется пошагово с начала файла. Это и позволяет сделать запуск «себя самого»:

self=`(readlink -f $0)`
java -jar $self 
exit

Проблема Windows

Microsoft как известно всегда идет своим путем, который затем навязывает окружающим. И их командный интерпретатор не стал исключением. Не думал, что вообще возможно сделать чтобы один и тот же скрипт выполнился как в Windows Batch так и в обычном bash. Но как ни странно решение нашлось. Скелет скрипта, который отрабатывает и в Windows и в bash вот:

rem(){ :;};rem '
@goto b
';echo Starting Demo..;

:b
@echo off
@echo Starting Demo...

Работает это за счет пересечения синтаксиса из двух миров: для Windows Batch rem это функция пропуска строки, те все что начинается со слова rem полностью пропускается вендовым интерпретатором. А вот для bash rem() это определение пустой функции и ее немедленный вызов с мультистрокой:

rem '
@goto b
';

Те фактически bash этот блок пропустит. А вот вендовый cmd.exe сделает переход по метке:

@goto b

В блок, где начинается уже полноценный код для Windows Batch:

:b
@echo off
@echo Starting Demo...

Вот таким чудным образом получается единая точка запуска для всего. И никакой магии.

Определение окружения

Чтобы запустить приложение на Java нужен рантайм — JRE, которого на машине может и не быть, либо он может быть устаревшей версии. Поэтому для полной радости, я добавил проверку версии и автоматическое скачивание JRE для Windows и Linux платформ. Для Linux учитывается тип архитектуры. Общая логика для Linux, FreeBSD и MacOS выглядит вот так:

echo "1. Searching for Java JRE.."
if type -p java; then
    echo "1.1 Found Java executable in PATH"
    _JRE=java
elif [[ -n $JAVA_HOME ]] && [[ -x "$JAVA_HOME/bin/java" ]];  then
    echo "1.2 Found Java executable in JAVA_HOME"
    _JRE="$JAVA_HOME/bin/java"
else
    echo "1.3 no JRE found"    
fi

v="$(jdk_version)"
echo "2. Detected Java version: $v"
if [[ $v -lt 8 ]]
then
    echo "2.1 Found unsupported version: $v"
    try_download_java
    echo "2.2 Using JRE: $_JRE"
fi
self=`(readlink -f $0)`
$_JRE -jar $self
exit

Сначала мы ищем «java» в виде команды, доступной из окружения. Если не нашли — проверяем наличие переменной JAVA_HOME в окружении (в этой переменной указывается обычно путь до JDK) Дальше проверяем версию найденной Java:

# returns the JDK version.
# 8 for 1.8.0_nn, 9 for 9-ea etc, and "no_java" for undetected
jdk_version() {
  local result
  local java_cmd
  if [[ -n $(type -p java) ]]
  then
    java_cmd=java
  elif [[ (-n "$JAVA_HOME") && (-x "$JAVA_HOME/bin/java") ]]
  then
    java_cmd="$JAVA_HOME/bin/java"
  fi
  local IFS=#x27;\n'
  # remove \r for Cygwin
  local lines=$("$java_cmd" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n')
  if [[ -z $java_cmd ]]
  then
    result=no_java
  else
    for line in $lines; do
      if [[ (-z $result) && ($line = *"version \""*) ]]
      then
        local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q')
        # on macOS, sed doesn't support '?'
        if [[ $ver = "1."* ]]
        then
          result=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q')
        else
          result=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q')
        fi
      fi
    done
  fi
  echo "$result"
}

Суть в том чтобы получить одно число, соответствующее мажорной версии найденной JRE: 8 — для Java 1.8, 9 — для Java 9, 11,14,19 и так далее. Эта функция вызывается, затем проверяется полученное число версии:

v="$(jdk_version)"
echo "2. Detected Java version: $v"
if [[ $v -lt 8 ]]
then
    echo "2.1 Found unsupported version: $v"
    try_download_java
    echo "2.2 Using JRE: $_JRE"
fi

Если найденная JRE слишком старая - пытаемся скачать. Но сначала проверяем есть ли уже скачанная версия:

UNPACKED_JRE=~/.jre/jre
if [[ -f "$UNPACKED_JRE/bin/java" ]]; then
    echo "3.1 Found unpacked JRE"
    _JRE="$UNPACKED_JRE/bin/java"
    return 0
fi

Вот так выглядит определение типа архитектуры и сопоставление части имени файла со скачиваемым JRE:

# Detect the platform (similar to $OSTYPE)
OS="`uname`"
ARCH="`uname -m`"
# select correct path segments based on CPU architecture and OS
case $ARCH in
   'x86_64')
     ARCH='x64'
     ;;
    'i686')
     ARCH='i586'
     ;;
    *)
    exit_error "Unsupported for automatic download"
     ;;
esac

Обратите внимание что 32битная система с линуксом будет называть себя i686, а в названии 32битной JRE будет i586. К сожалению бинарных сборок в виде скачиваемого архива для FreeBSD и MacOS нет, поэтому пока вот так:

case $OS in
  'Linux')
    OS='linux'
    ;;
  *)
    exit_error "Unsupported for automatic download"
     ;;
esac

Эти параметры затем подставляются в полную ссылку для скачивания:

echo "3.2 Downloading for OS: $OS and arch: $ARCH"
URL="https://../../jvm/com/oracle/jre/1.8.121/jre-1.8.121-$OS-$ARCH.zip"
echo "Full url: $URL"

Откуда берется JRE

Вообще Oracle не дает скачивать релизы JRE в автоматическом режиме, поэтому для тестов выложили бинарные сборки OpenJDK и JRE в виде зависимостей Maven, вот тут. Это устаревшая 1.8 версия, но для PoC прототипа хватит. Ниже опишу логику работы скрипта. Вот так происходит скачивание и распаковка:

echo "Full url: $URL"
CODE=$(curl -L -w '%{http_code}' -o /tmp/jre.zip -C - $URL)
if [[ "$CODE" =~ ^2 ]]; then
    # Server returned 2xx response
    mkdir -p ~/.jre
    unzip /tmp/jre.zip -d ~/.jre/
    _JRE="$UNPACKED_JRE/bin/java"
    return 0
elif [[ "$CODE" = 404 ]]; then
    exit_error "3.3 Unable to download JRE from $URL"
else
    exit_error "3.4 ERROR: server returned HTTP code $CODE"
fi

По идее нужно еще отдельно проверять возвращаемые коды при создании каталога и распаковке — но для PoC думаю и текущей логики хватит.

Часть с Windows

Теперь детально разберем часть скрипта, отвечающего за венду. Вот отсюда она начинается:

:b
@echo off
@echo Starting Demo...
:: self script name
set SELF_SCRIPT=%0

Первым делом сохраняем полный путь до себя самого (%0) в переменную SELF_SCRIPT, тк дальше он может быть перезаписан. Дальше определяем путь до распакованной JRE, которая будет храниться в домашней папке текущего пользователя:

:: path to unpacked JRE
set UNPACKED_JRE_DIR=%UserProfile%\.jre
:: path to unpacked JRE binary
set UNPACKED_JRE=%UNPACKED_JRE_DIR%\jre\bin\javaw.exe

IF exist %UNPACKED_JRE% (goto :RunJavaUnpacked)

Если бинарник JRE существует — считаем что JRE уже был скачан и используем его. Обратите внимание на особенность вендов, в виде отдельного бинарника для графических приложений: javaw.exe Если скачанного JRE нет — пытаемся найти в окружении. Если нашли — пытаемся определить версию:

where javaw 2>NUL
if "%ERRORLEVEL%"=="0" (call :JavaFound) else (call :NoJava)
goto :EOF
:JavaFound
set JRE=javaw
echo Java found in PATH, checking version..
set JAVA_VERSION=0
for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do (
  set JAVA_VERSION=%%g
)
set JAVA_VERSION=%JAVA_VERSION:"=%
for /f "delims=.-_ tokens=1-2" %%v in ("%JAVA_VERSION%") do (
  if /I "%%v" EQU "1" (
    set JAVA_VERSION=%%w
  ) else (
    set JAVA_VERSION=%%v
  )
)

Считаем, что если есть javaw.exe то есть и java.exe, поскольку в вендовых сборках оба бинарника обязательно присутствуют в папке bin. Общий смысл кода выше ровно такой же что и для bash версии - получить мажорную цифру версии JRE для последующей проверки: if %JAVA_VERSION% LSS 8 (goto :DownloadJava) else (goto :RunJava) Если найденная JRE старше 1.8 — считаем что она не поддерживается и пытаемся скачать. Вот так выглядит скачивание и распаковка JRE:

:DownloadJava
echo JRE not found in PATH, trying to download..
WHERE curl
IF %ERRORLEVEL% NEQ 0 (call :ExitError "curl wasn't found in PATH, cannot download JRE") 
WHERE tar
IF %ERRORLEVEL% NEQ 0 (call :ExitError "tar wasn't found in PATH, cannot download JRE")  
curl.exe -o %TEMP%\jre.zip  -C - https://nexus.nuiton.org/nexus/content/repositories/jvm/com/oracle/jre/1.8.121/jre-1.8.121-windows-i586.zip
IF not exist %UNPACKED_JRE_DIR% (mkdir %UNPACKED_JRE_DIR%)
tar -xf %TEMP%\jre.zip -C %UNPACKED_JRE_DIR%

Важные моменты:

Глаза вам не врут: curl и tar теперь действительно есть в Windows. На самом деле аж с 2017 года.
Используем одну универсальную 32х битную версию JRE, без учета архитектуры, поскольку на Windows нет проблемы совместимости и запуска 32х битных приложений на x86_64 архитектуре. Ну и это все же PoC для тестирования а не жирный продакшн. Код запуска выглядит вот так:

:RunJavaUnpacked
set JRE=%UNPACKED_JRE_DIR%\jre\bin\javaw.exe
:RunJava
echo Using JRE %JAVA_VERSION% from %JRE%
start %JRE% -jar %SELF_SCRIPT%
goto :EOF
:ExitError
echo Found Error: %0
pause
:EOF
exit
Тут необходимо пояснить про ссылочную логику и метки. Команда goto делает переход в место скрипта отмеченное меткой:
goto :EOF
перейдет вот сюда, минуя весь остальной код:
:EOF
exit

А если метки нет то выполнение продолжится последовательно, поэтому после:

set JRE=%UNPACKED_JRE_DIR%\jre\bin\javaw.exe

выполнится:

echo Using JRE %JAVA_VERSION% from %JRE%

И дальше до конца.

MacOS и readlink

Оказалось что реализация readlink на маке не поддерживает ключ -f ,несмотря на все визги про то что MacOS это тоже BSD. Поэтому пришлось добавлять реализацию прямо в скрипт:

# Return the canonicalized path (works on OS-X like 'readlink -f' on Linux); . is $PWD
function get_realpath {
    [ "." = "${1}" ] && n=${PWD} || n=${1}; while nn=$( readlink -n "$n" ); do n=$nn; done; echo "$n"
}

Эта функция используется для вычисления собственного полного пути, с учетом ссылок и относительных частей. Шелл по-умолчанию В MacOS начиная с Catalina по-умолчанию используется zsh, в FreeBSD - ksh а в большинстве линуксов - bash. Код загрузчика для юниксов в этом проекте написан для bash.

Чтобы автоматически перезапустить скрипт через bash, если пользователь запускает другим интерпретатором, используется вот такой код:

if [ -z "$BASH" ]; then 
echo "0. Current shell is not bash. Trying to re-run with bash.." 
exec bash $0
exit
fi

Тестовый проект

Весь проект выложен на Github вот тут. Имейте ввиду что две части шелл-скрипта - для Windows Batch и для bash имеют разную настройку окончания строк! Это оказалось обязательным для запуска на MacOS. Само тестовое приложение на Swing, примечательно циклом сборки. Я использовал BeanShell plugin, для того чтобы реализовать логику упаковки в виде inline-скрипта на самой Java:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.Ox08.experiments</groupId>
    <artifactId>full-cross</artifactId>
    <version>1.0-RELEASE</version>
    <name>0x08 Experiments: Full Cross Application</name>
    <packaging>jar</packaging>
    <url>https://teletype.in/@alex0x08</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <exec.mainClass>com.ox08.demos.fullcross.FullCross</exec.mainClass>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.ox08.demos.fullcross.FullCross</mainClass>
                        </manifest>                       
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.genthaler</groupId>
                <artifactId>beanshell-maven-plugin</artifactId>
                <version>1.4</version>                
                <executions>
               <execution>
                  <phase>package</phase>
                  <goals>
                     <goal>run</goal>
                  </goals>
               </execution>
            </executions>
                <configuration>
                    <quiet>true</quiet>                
                    <script>
                <![CDATA[
                        import java.io.*; 
                        // function should be defined before actual call
                        // this just appends source binary to target
                         void copy(File src,OutputStream fout) {
                            FileInputStream fin = null;
                            try {    
                            fin =new FileInputStream(src);                         
                            byte[] b = new byte[1024];
                            int noOfBytes = 0; 
                            while( (noOfBytes = fin.read(b)) != -1 )
                            { fout.write(b, 0, noOfBytes);  } 
                            } catch (Exception e) {
                                e.printStackTrace();
                            } finally {
                                fout.flush();
                                if (fin!=null) { fin.close(); }
                            }                             
                        }                  
                        // current project folder                                           
                        String projectDir = System.getProperty("maven.multiModuleProjectDirectory");
                        // target combined binary
                        File target = new File(projectDir+"/target/all.cmd");    
                        if (target.exists()) {
                            target.delete();
                        }            
                        // shell bootloader
                        File fboot = new File(projectDir+"/src/main/cmd/boot.cmd");                
                        // jar file with application    
                        File fjar = new File(projectDir+"/target/full-cross-1.0-RELEASE.jar");                
                        // open write stream to target combined binary
                        FileOutputStream fout = new FileOutputStream(target);
                        // write bootloader
                        copy(fboot,fout);
                        // write jar
                        copy(fjar,fout);
                        fout.close();
                        target.setExecutable(true);
                ]]>
                    </script>
                </configuration>                
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <version>3.1.1</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
          </plugins>
    </build>
</project>

Собирается абсолютно любой JDK cтарше 1.8 версии:

mvn clean package

Можно использовать внешний Apache Maven, либо собрать из любой среды разработки. Итоговый бинарник будет в папке target.

Нехорошие дела

Полагаю у некоторых читателей далеких от ИБ, появилась мысль о возможности нехорошего применения этой технологии: сваять какую-нибудь кроссплатформенную малварь/шифровальщик/вирь и все в этом духе.

На самом деле так заморачиваться никому не интересно - объем кода, который делает эскалацию привилегий в системе, открывает бекдор или творит еще какую дичь и так немаленький. Тащить три разных версии такого кода, под разные ОС, с собой в одном бинарнике - ну совсем перебор.

Второй важный момент - командный интерпретатор выполняется пошагово, там нет тредов, поэтому весь код отлично просматривается любыми антивирусами, даже самыми тупыми. Вообщем не интересно это нормальным бандитам.

Выводы

В принципе Америку я не открыл - такое известно давно и давно используется на практике. Вот тут находится огромная статья с примерами на разных языках.

Вот тут находится проект для создания кросс-платформенных самораспаковывающихся архивов под разные типы Unix, используется та же идея.

Тем не менее, полную сборку в готовое решение, с кроссплатформенностью «Windows-Mac-Linux-BSD» для одного бинарника я еще не видел.

Поэтому сие является моим уникальным контентом, хоть и развитием старых идей.

Практическое применение такой штуки очень даже возможно и имеет смысл, поскольку исчезает необходимость генерации нескольких разных сборок под разные ОС. Но естественно что нужно будет больше работы по оптимизации стартовых скриптов.

P.S: Иконку на такой бинарь к сожалению не поставить, увы.

★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 8)

Ответ на: комментарий от alex0x08

Какой нахрен ящик, любое производственное предприятие с сертифицированной СКС так работает.

Xintrea ★★★★★
()
Ответ на: комментарий от alex0x08

Скрипт же сам скачивает JRE

не ентерпрайзно жЫ!

  1. может не быть инета

  2. EMCя, например, с собой таскает JRE

я это к тому, что было бы толково сперва заначку проверять локальную, какой-нибудь well-known path сперва (Downloads и т.п.)

mumpster ★★★★★
()
Ответ на: комментарий от alex0x08

дык прочитал!
сам же пишешь, что оракл не даёт нормально скачать

плюс моё знание реалий

это просто предложение это часть улучшить упрощением - жаба либо должна уже быть на месте, либо лежать в условленном месте, откуда ты, так и быть, её распакуешь и поставишь.

это нормальная практика.

а за раздачу помимо них оракл может и натянуть…

не хочешь, не слушай советов, дело твоё.

mumpster ★★★★★
()
Ответ на: комментарий от mumpster

Я даже не знаю что тебе сказать:

Сначала мы ищем «java» в виде команды, доступной из окружения. >Если не нашли — проверяем наличие переменной JAVA_HOME в >окружении (в этой переменной указывается обычно путь до JDK) >Дальше проверяем версию найденной Java

Чтобы запустить приложение на Java нужен рантайм — JRE, которого >на машине может и не быть, либо он может быть устаревшей версии. >Поэтому для полной радости, я добавил проверку версии и >автоматическое скачивание JRE для Windows и Linux платформ. Для >Linux учитывается тип архитектуры

JRE выложен вот тут и давно:

https://mvnrepository.com/artifact/com.oracle.java/jre

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

а не надо уже ничего говорить, всё понятно

повторю добрый совет:

а за раздачу помимо них оракл может и натянуть…

written consent есть вообще?

mumpster ★★★★★
()
Ответ на: комментарий от mumpster

а за раздачу помимо них оракл может и натянуть…

Смешно звучит, на нынешние времена-то.

Вчера скачивал драйвера для Intel-карты, так пришлось впн поднимать, поскольку Интел решил что раз он ушел из РФ, то я как его кастомер с договором поддержки перестал существовать.

alex0x08 ★★★
() автор топика

Респект, круто, впечатляет! И как PoC в целом, и за объём проделанной работы.

Да, можно было это обернуть в ансибл+доцкер, например, но и так суть понятна и в принципе штука может найти себе применение в продакшене.

yu-boot ★★★★
()
Ответ на: комментарий от yu-boot

Да, можно было это обернуть в ансибл+доцкер,

Вам дай волю - вы и bash в докер закатаете )

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

смешно или не смешно, но мы ходим по тонкому льду.

ВНЕЗАПНО суды «этой страны» продолжают выносить решения в пользу копирастов. это например. ну или поедешь в Тай отдыхать, а там тя неожиданно под жабры, как Бута.;-)

поэтому лично я предпочитаю не вляпываться там где без этого можно обойтись. но хозяин - барин, да.

да к тому же это не решает проблему с возможным отсутствием инета по месту применения.

это очень распространённая проблема. и минус приладе. прилада-то твоя хорошая по задумке.

mumpster ★★★★★
()
Ответ на: комментарий от mumpster

поэтому лично я предпочитаю не вляпываться там где без этого можно обойтись.

я лишь скромно надеюсь что дело пока не дошло до надевания двух презервативов за раз ради надежности.

да к тому же это не решает проблему с возможным отсутствием инета по месту применения.

Тут придется потрудиться: установить готовый пакет JRE, который присутствует абсолютно в любом линуксе,солярисе, hp-ux,aix,qnx, маке, виндах и во всех BSD. Это невероятно сложная задача. И безумно редкая.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

А интернет сейчас есть везде.

Нет. Вот примеры:

  1. Натурально нищие люди, где-то раздобывшие локалхост.
  2. Люди, которые раздобыли компьютер для ребенка, но сами им не пользуются. Ребенок будет резаться в игрушки локально, готовить презентации и рефераты преимущественно локально, а для выхода в мир использовать USB tethering, Wi-Fi hotspot или мобилу непосредственно.
  3. Жители глуши, где спутниковый интернет мало кто может себе позволить, витухи и PON нет, ADSL недоступен из-за пупинизации или потому что проводной телефон отрезан экономной бабушкой с Nokia 3310.
  4. Нищие бюджетные учреждения или бюджетные учреждения с консервативным руководством. Те же школы могут финансироваться очень по-разному, а руководить ими могут люди старой закалки. Где-то интернета просто не будет. Где-то есть интернет в кабинете информатики, но нет у директора. Где-то стоит единственный компьютер, за которым все поочередно готовят документы, и из сетей там только 127.0.0.0/8.
  5. Режимные объекты. Кое-где из соображений безопасности исползуется изолированный от мира интранет.
Vidrele ★★
()
Ответ на: комментарий от Vidrele

Ужас какой, «дети голодают» о боже мой.

Друг, если хочешь рассказать что «статья херня и автор дурак» - есть способ лучше: пройдись по коду, там все далеко не идеально. Предложи свое решение, которое будет лучше.

А пердеть тут «общечеловеческими ценностями» не надо.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Я к тому, что хосты без интернета встречаются и в домах, и на предприятиях. Безотносительно того, хорошо это или плохо, херня или не херня статья, дурак или не дурак автор.

Vidrele ★★
()
Ответ на: комментарий от Vidrele

более того, я на таких постоянно бываю и живьём и удалённо. и нет проблем заиметь там жабу или что ещё, но вот скачать её напрямую - никак.

mumpster ★★★★★
()
Ответ на: комментарий от mumpster

Как ты бываешь удаленно на хостах без интернета (и без возможности заиметь его краткосрочно, чтобы скачать жабу)? LAN/CAN/MAN? Или там Интернет есть, но фаерволами фильтруется всё, кроме VPN? Или, может быть, дозваниваешься на модем?

Vidrele ★★
()
Ответ на: комментарий от Vidrele

да, intranet через vpn

и строго говоря, у Ethernet тоже есть «модем» - модулятор-демодулятор, например, MLT-3 или 4B5B для сотки, PAM-5 и 8B10B для гигабита

mumpster ★★★★★
()
Ответ на: комментарий от mumpster

Если задуматься, модуляцию-демодуляцию можно разглядеть в любой семантической системе. Идет кобель мимо дерева: сзади - модулятор, спереди - демодулятор.

Vidrele ★★
()
Ответ на: комментарий от Vidrele

ещё раз повторюсь, что с чисто технической точки зрения нет особой разницы между тем, что делал т.н. «модем для телефонной линии» и сетевая плата со встроенным PHY.

тем более что есть масса модемов для выделенных телефонных линий, которые используют тот же PAM, что медный Ethernet.

mumpster ★★★★★
()
Ответ на: комментарий от alex0x08

сделал универсальный бинарник

твой бинарник так себе, так как неявно ставит внешнюю зависимость

ррря, жалуйся касперскому

Все ясно. Уже написал в спортлото

Aswed ★★★★★
()
Ответ на: комментарий от Aswed

Не нравится? - возьми и сделай сам свою версию. А выкатывать «лошадиные предъявы» не надо, не поймут.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

не поймут

Кто не поймет? По-моему все все поняли.

Aswed ★★★★★
()

Автору респект, но что если не останавливаться на этом и подготовить удобный визард console/TUI/GUI для создания таких паков?

Windows-Mac-Linux-BSD

А если еще Linux/x86/arm/etc ???

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Чтобы серьезно вкладываться в разработку надо понимать кому это примерно будет надо.

Пока это не очевидно.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

У тебя что ни комментарий, то желчь и абьюз. Ты сам осуждал в своём блоге мещанство и российский менталитет программистов. А тут на ЛОРе просто брызжешь нетерпимостью и обесцениваешь высказывания и позиции других.

Какой-то обиженный на жизнь дед.

ForrestMike
()
Ответ на: комментарий от ForrestMike

Аргумент про то что интернет в 21м веке доступен не всем - откровенный троллинг, причем толстый. Тем более на ЛОРе и в комментах к статье про PoC и эксперименты.

Это примерно как предъявлять претензии к интерфейсу управления атомной станцией - что де слишком много всяких индикаторов и кнопочек, дети и пожилые не разберутся.

Если есть что по делу обсудить - без проблем, но вот такой толстый троллинг откровенно не интересен уже.

alex0x08 ★★★
() автор топика

Я больше горжусь что такой PoC вообще смог реализовать, к чему привело в том числе и чтение SICP и «книги дракона» и еще кучи «всякого старья»

Вот это и надо было написать. Просто, скромно и непринужденно. И в толксы одним предложением. бгг

Gonzo ★★★★★
()
29 мая 2023 г.
Ответ на: комментарий от alex0x08

Аргумент про то что интернет в 21м веке доступен не всем - откровенный троллинг, причем толстый

То есть вариант когда интернет есть но ппц дорогой ты не рассматриваешь? Например если я поеду сейчас встретиться с коллегой, до которого мне 15 мин ходу, то моя симка внезапно уйдёт в международный роуминг (и правда, с чего бы, подумаешь границу пересёк), и дальше как только я вылечу за 500мб трафика будет 3 бакса за метр. Такая себе «доступность»

upcFrost ★★★★★
()

Ох, сколько костылей…

Для macOS можно проще (как — надо тестить, у меня под рукой нет).

Также не вижу решения для FreeBSD и без bash. ☺

mord0d ★★★★★
()
Ответ на: комментарий от upcFrost

Скачивание опционально, идет как последний возможный шаг перед тем как написать пользователю «извините не шмогла». Перед ним идет поиск установленной JDK/JRE фактически любой версии начиная с 1.8.

Ну и еще раз: это PoC а не реальное приложение. Скачивание я добавил прежде чем скидывать своим друзьям - чтобы они смогли протестить не качая джаву вручную.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от mord0d

Также не вижу решения для FreeBSD и без bash

Вот это уже продакшн, не PoC. Доводить скриптовую часть чтобы она работала везде: zsh,ksh,csh и так далее - очевидно сложно и значительно дольше.

Одного мака хватило, где пришлось readlink -f реализовывать.

Т.е в формат PoC + статья это точно не укладывается. Будет интерес по реальному применению (чего я пока не наблюдаю) - реализую.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Одного мака хватило, где пришлось readlink -f реализовывать.

А чем тебе realpath(1) не угодил? Я, например, в своей скриптоте уже давно отказался от readlink -f (он же stat -Lf '%R' <file>) в пользу realpath, доволен как кот.

Доводить скриптовую часть чтобы она работала везде: zsh,ksh,csh и так далее - очевидно сложно и значительно дольше.

Нуу… bash↔zsh по большей части можно одним скриптом реализовать, но учесть особенности обоих (покроет сразу и Linux и macOS). ksh это у нас OpenBSD и… всё? Даже в солярке нынче по дефолту /bin/sh. С csh всё ещё лучше: его юзают только такие отбитые персонажи как я (раньше оно по дефолту стояло для root, но с последним релизом дефолтом стал sh), но и тут всегда можно просто запустить sh, который есть решительно везде в том или ином виде.

У тебя по сути есть две проблемы:

  • Наличие шелла (я думаю, тебя не удивит что /bin/sh есть не везде и/или не по дефолтному пути?);
  • Наличие вспомогательных утилит (тот же readlink в macOS тебе пришлось изобретать, хотя можно было просто взять realpath).

Если на всех нужных платформах есть совместимый с POSIX Shell (даже если это Bash в режиме совместимости), то первая проблема решается через тот же #!/usr/bin/env sh. Вторая решается назначением переменных или даже целых функций через какой-нибудь case "$(uname -s)" или вообще банальнейший . ./$(uname -s).sh || exit 1 (да, source это уже башизм, но в bash всё ещё работет ., как минимум в режиме совместимости; а вот в zsh можно использовать только source, как и в csh, но там синтаксис вообще несовместим, да и не пригоден он для скриптоты… поверь, я пытался ☺), и дальше уже вместо бинарей дёргать переменные/функции.

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Наличие шелла (я думаю, тебя не удивит что /bin/sh есть не везде и/или не по дефолтному пути?);

Удивит, не видел чтобы /bin/sh не был доступен. Это же shebang для automake скриптов - куда уж кроссплатформенней. То что в Солярисе bash может быть где-то в /opt это я понимаю, но /bin/sh же все равно есть всегда и везде по этому пути. Где ты видел чтобы /bin/sh не было?

ksh это у нас OpenBSD и… всё?

Это все BSD и особо олдовые линуксоиды. Во всех BSD korn shell есть.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Удивит, не видел чтобы /bin/sh не был доступен.

Я видел это на каком-то маргинальном, но enterprise-ориентированном дистрибутиве Linux. Там оно было то ли /usr/bin/sh, то ли ещё где, не помню уже.

Это же shebang для automake скриптов - куда уж кроссплатформенней.

Automake это, внезапно, линуксизм.

Ну и, опять же внезапно, оно не обязано работать вот прям везде: нужно компилять — ставь нужный софт, подготавливай окружение, так всегда было, а уже потом все обленились и полагаются на дефолт своего дистрибутива, свято веря что везде так.

То что в Солярисе bash может быть где-то в /opt это я понимаю, но /bin/sh же все равно есть всегда и везде по этому пути.

Ты путаешь UNIX-like и POSIX-compliant. Юникс не обязан быть позикс-совместимым. ☺

Я тебе даже больше скажу: GNU, яро пропихивая POSIX, в итоге сами на него забили.

Во всех BSD korn shell есть.

Во FreeBSD нет ksh, только (t)csh и сильно пропатченный ash. Про другие не знаю, не могу сказать. Слышал что в OpenBSD ksh является дефолтным шеллом по умолчанию.

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Во FreeBSD нет ksh, только (t)csh и сильно пропатченный ash.

Есть, даже три версии:

ksh-1.0.4                      Development branch of AT&T KornShell 93
ksh-devel-2023.03.30           ksh93u+m is the development branch ksh93 based on AT&T ksh93u+ (stable)
ksh93-93.u_3,2                 AT&T KornShell ksh93u+ 2012-08-01 (stable) version

Я тебе из-под FreeBSD и пишу, так что могу точно сказать.

Слышал что в OpenBSD ksh является дефолтным шеллом по умолчанию

Не очень понял. Есть useradd, которым создается новый пользователь в системе, при создании ему указывается какой шелл будет запускаться по-умолчанию.

Но на уровне ОС никакого ‘дефолтного’ шелла нет, их всегда несколько разных устанавливается при установке ОС.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Во FreeBSD нет ksh, только (t)csh и сильно пропатченный ash.

Есть, даже три версии

Их нет в базовой системе.

И установятся они в /usr/local.

Я тебе из-под FreeBSD и пишу, так что могу точно сказать.

# uname -srm
FreeBSD 13.2-RELEASE amd64
# freebsd-version -kru
13.2-RELEASE
13.2-RELEASE
13.2-RELEASE

То что можно установить это уже совсем другая история, твоё автоопределение должно будет не только определить отсутствующую зависимость, но ещё и установить её (что требует повышения прав), иначе толку от всех этих телодвижений мало.

Не очень понял. Есть useradd, которым создается новый пользователь в системе, при создании ему указывается какой шелл будет запускаться по-умолчанию.

Ты хочешь ещё и в настройки пользователей влезть?!

Но на уровне ОС никакого ‘дефолтного’ шелла нет, их всегда несколько разных устанавливается при установке ОС.

В ОС не может не быть user shell (пользовательской оболочки), иначе пользователь не сможет взаимодействовать с компьютером. В том числе не сможет скомандовать компьютеру установить шелл!

В DOS это был COMMAND.COM (дефолтный, заметь!), в BSD это был /bin/sh.

Формально даже Windows имеет user shell, но уже только графический (командный есть, но он может быть дефолтным — Windows не поддерживает ни только-командный режим (причём даже Windows Server), ни смену шелла (но как минимум раньше поверх него можно было запустить обёртки)). В macOS примерно та же история с некоторыми поправками на то что это UNIX (сертифицированный, потому не -like).

А Linux это не ОС, это ядро, потому и шелла в нём нет.

mord0d ★★★★★
()

Мда, захейтели автора, за то что его статья с примером скрипта, неожиданно не угодила всем.

Поправить код на то, чтобы Ява не качалась, а устанавливалась с локальной папки, оказывается беда прям.

Друзья, скрипт не универсальный. Его все равно придется допиливать под определенные задачи

admucher ★★
()
Ответ на: комментарий от mord0d

То что можно установить это уже совсем другая история,

А я с чего-то думал что речь про само наличие ksh под фрей, не про пакет/база.

Но вообще удивлен - раньше же ksh был в базе? Неужели настолько устарел что выкинули в пакет?

твоё автоопределение должно будет не только определить отсутствующую зависимость, но ещё и установить её (что требует повышения прав), иначе толку от всех этих телодвижений мало.

Очевидно что это уже перебор, от слова совсем. И делать такое не имеет смысла.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от admucher

Тут рядом точно также не угодила всем моя статья про Мак и KVM, а до этого неугодили пять или шесть сложных скриншотов подряд, где под каждым практически было по статье. Но это нормально для ЛОРа, тут всегда так было.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

А я с чего-то думал что речь про само наличие ksh под фрей, не про пакет/база.

Ну ты же автоматизацию пишешь, тут нельзя полагаться на софт, которого может не быть. Или предлагаешь писать инструкцию как пользоваться твоей упрощалкой жизни длиннее кода самой упрощалки? ☺

раньше же ksh был в базе?

Во фре его никогда не было. Оригинальный ksh написан AT&T, его код распространять вместе с базой не получилось бы, а свободные для распространения реализации подъехали уже позже.

Очевидно что это уже перебор

Я к этому изначально и веду: нельзя полагаться на компоненты, которых может не быть. Я уже проходил подобный квест несколько раз.

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Ну ты же автоматизацию пишешь, тут нельзя полагаться на софт, которого может не быть.

Это не то чтобы автоматизация, скорее usability - удобство для конечного юзера.

Но сколько отсматривал скрипты запуска чужих приложений - всегда есть некий уровень допущений, ниже которых разработчики не лезут и просто пишут ошибку.

И воообщем-то это правильно, иначе можно очень закопаться и переусложнить скрипт.

Я к этому изначально и веду: нельзя полагаться на компоненты, которых может не быть.

А почему нет? Если это ради того чтобы выполниться любой ценой - так могут например кончиться свободные дескрипторы файлов и тогда скрипт даже сам себя на bash переключить не сможет. Может кончиться память на любом шаге и упадет даже grep какой-нибудь.

Посмотри на это под другим углом: отстуствие чего-то необходимого в окружении - повод для аварийной остановки и все.

Сама идея скрипта в том что скрипт - высокоуровневая абстракция, которая не должна решать низкоуровневые проблемы.

Ну и потом если говорить про выполнение любой ценой и ультранадежность, тогда надо отказываться от любого графического интерфейса вообще и идти по пути cosmopolitan (который выше описали), потому что зависимостей от откружения в JRE сильно больше чем в любом скрипте.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от annulen

нельзя полагаться на компоненты, которых может не быть

Их просто нужно заявлять как prerequisites :)

Любая утилита должна быть самодостаточной.

mord0d ★★★★★
()
Ответ на: комментарий от alex0x08

Ну ты же автоматизацию пишешь, тут нельзя полагаться на софт, которого может не быть.

Это не то чтобы автоматизация, скорее usability - удобство для конечного юзера.

А удобно ли будет пользователю держать в голове или вычитывать из документации списки зависимостей для каждой используемой им платформы, ставить их и вообще? ^_~

И воообщем-то это правильно, иначе можно очень закопаться и переусложнить скрипт.

У меня есть скрипт, просто раскидывающий конфиги по хостам. На ≈800SLOC!

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

А удобно ли будет пользователю держать в голове

Тут явное непонимание что такое пользователь ) То что я реализовал оно не про культуру UNIX, от слова совсем. Это для современных великовозрастных детей, которым надо нажать и чтоб оно заработало.

или вычитывать из документации списки зависимостей для каждой используемой им платформы, ставить их и вообще? ^_~

Люди книги уже не читают, договора подписывают не читая, а ты про какую-то «документацию».
Сейчас программирование и то изучают по ютубу )

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Тут явное непонимание что такое пользователь

Я-то как раз понимаю что из себя представляет современный пользователь. Это тупая обезьянка, которая решает проблемы копипастой из интернетов. Пользоваться мозгом нынче не модно и, вероятно, даже как-то зазорно. Если ты умный, то ты долбо…

надо нажать и чтоб оно заработало

И вот для этого нужно ещё работать и работать. Чтобы оно просто заработало, нужно решить все проблемы, с которыми пользователь может (даже если эта вероятность близится к нулю) столкнуться.

про культуру UNIX

Так и она уже не та. И популяризация Linux была основным фактором. Причём изменившееся сообщество повлияло на Linux, и теперь он идёт по пути Windows (догоняющий всегда отстаёт).

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Я-то как раз понимаю что из себя представляет современный пользователь. Чтобы оно просто заработало, нужно решить все проблемы, с которыми пользователь может (даже если эта вероятность близится к нулю) столкнуться.

Видимо все-таки нет понимания.
Чтобы обслуживать тупых и предсказуемых нужно предсказуемое, унифицированное окружение. На сейчас таких три: мак, венды и убунту.

Ну можно еще что-то средне-универсальное сделать под популярные линуксы но и только. Для всех остальных (в первую очередь BSD) нужна инструкция и описание - самим пользователям так проще, они привыкли разбираться сами.

Кстати сам факт запуска их софта на BSD часто вендора вгоняет в ступор - они просто не готовы к тому что пользователь может быть умнее и технически более грамотным чем его собственные разработчики.

alex0x08 ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.