Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги хакеры / журнал хакер / специальные выпуски / Специальный выпуск 51_Optimized

.pdf
Скачиваний:
14
Добавлен:
20.04.2024
Размер:
8.45 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

IDE Anjuta в действии

включает все виды оптимизаций, включающихся ключом "O2", которые не увеличивают размер выходного кода. Плюс еще кое-что. За более подробной информацией обращайся к info-страницам по GCC.

Для отладки написанной программы необходимо совершить еще одно телодвижение - добавить отладочную информацию к программе. Для этого при компиляции (с использованием GCC) необходимо добавить ключ "-g". Именно он и сделает то, что нам нужно. Вообще, отладочная информация может быть представлена в нескольких форматах. Один из них - формат, "разработанный" специально для использования с gdb. Для осуществления этого есть специальный ключ - "-ggdb".

Одной интересной особенностью компилятора GCC является тот факт, что ключи g и O<x> могут быть использованы одновременно. Так можно попросить компилятор оптимизировать код, а затем добавить отладоч- ную информацию. И в итоге получа- ешь результаты такой оптимизации в наглядном виде. Некоторые константы и переменные могут исчезнуть, блоки кода - изменить свое положение в программе. А некоторые - вообще не исполняться, так как их результат заранее можно просчитать и он никогда не меняется. Кстати, можно задать количество отладочной информации, помещаемой в результирующий файл. Всего существует три уровня, второй используется по умол- чанию. Задается все ключом "-g<x>" или "-ggdb<x>". Уровень один - минимум, уровень три - максимум (добавляется информация о макросах в программе). Такие вот дела.

НАЧИНАЕМ

Итак, теперь перейдем к главному: программированию на C. По-моему, здесь все поделено на две части: использование системных вызовов ядра ОС, предоставляющих некоторые основные функции, и использование

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

Если твои программы соответствуют стандарту ANSI C или C99, то они будут легко компилироваться под любой ОС с использованием "правильного" компилятора. Однако стремление к соответствию упомянутым стандартам, к сожалению, не разбудит полностью все таланты системы.

Для любой *nix-программы, помимо стандартных заголовков stdlib.h & stdio.h, необходимо использование заголовка unistd.h. При использовании некоторых специфичных типов данных необходимо подключать заголовок sys/types.h.

Для примера рассмотрим основные функции (примитивы) для работы с файлами, предоставляемые любой *unix-системой. Эти функции состоят из небольшого набора системных вызовов, обеспечивающих непосредственный доступ к средствам ввода\вывода ОС. Одновременно с этим они являются основой для всей системы ввода\вывода *nix, и многие другие механизмы доступа к файлам (например) основаны именно на них.

Вот они: Open - открытие файла, Close - закрытие, Read - чтение данных, Write - запись данных, Lseek - перемещение в заданную позицию в файле, Fcntl - управление связанными с файлом атрибутами.

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

79

Ближе к делу - рассмотрим элементарный рабочий пример:

#include <unistd.h> #include <fcntl.h> #include <sys/types.h>

int main () { int fd;

ssize_t nread; char buf[1024];

fd = open("data", O_RDONLY); nread = read(fd, buf, 1024); close(fd);

};

Вызов Open открывает в текущем каталоге файл Data только для чтения, возвращая целочисленный (и неотрицательный) дескриптор файла, по которому система уже будет опознавать этот файл и предоставлять возможность выполнять с ним нужные действия. Далее идет системный вызов Read, читающий из файла с идентификатором fd первый килобайт данных. Все не так сложно.

Стоит заметить, что в случае возникновения ошибки любой из используемых выше системных вызовов вернет - 1. Чтобы узнать точное значе- ние ошибки - подключить заголовоч- ный файл errno.h и посмотреть значе- ние переменной Errno. Или вызвать функцию Perror(), которая выведет текстовую интерпретацию ошибки на экран.

Внимание! Вызов Open имеет три параметра (последний - необязательный): строка, содержащая название файла, после которой идет целочисленный метод доступа. В этом случае использован O_RDONLY - только чтение. Также возможно использование O_WRONLY (только запись), O_RDWR (открытие для чтения и записи) или значение O_CREAT, используемое для создания файла. Как всегда, комбинировать значения можно при помощи "|" (например, O_CREAT | O_WRONLY). При использовании зна- чения O_CREAT нужно передать системному вызову и третий параметр типа mode_t (на самом деле он тоже целочисленный), который будет характеризовать права доступа. Кстати, есть еще одно полезное значение второго параметра - O_TRUNC. При его использовании вместе с флагом O_CREAT файл будет усечен до нулевого размера (если он существует и если это позволяют права доступа).

Напоминаю, что после завершения работы файл нужно обязательно закрыть - системный вызов Close. Напоминаю и про существование man'ов по этим системным вызовам, в которых можно найти намного более подробную информацию.

Не стоит забывать про функцию Fcntl, используемую для управления уже открытыми файлами. Она определена как int fcntl(int fd, int cmd, <что-то зависящее от cmd>). Больше других »

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

 

* N I X

 

Читай, читай, читай и еще раз читай man'ы - если какая-то информация гдето от тебя пря- чется, то именно там.

Из сред разработки под *nix могу предложить таких монстров, как, например, KDevelop, Anjuta. Это из Иксовых, под КДЕ и GNOME соответственно.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

80 CODING CВ*NIX-ЗАЛОГЗДОРОВЬЯ

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

* N I X Á Å Ç

Кроссплатформенные библиотеки в действии

Системные вызовы ввода\вывода являются основой всей системы ввода\вывода *nix, но они примитивны и предоставляют возможность работы с данными в виде простой последовательности байт.

Читай man'ы и посещай (очень советую) www.tldp.org, содержащий огромное коли- чество самой разной увлекательной и познавательной информации по Linux.

интересны значения параметра cmd F_GETFL & F_SETFL. Они позволяют узнать\изменить текущие флаги статуса открытого файла. Вот как, например, можно узнать текущий статус файла (модификатор доступа):

int arg = fcntl(fd, F_GETFL); if (arg & O_APPEND)

printf("ôëàã O_APPEND");

if ((arg & O_ACCMODE) == O_RDWR) printf("файл открыт для чтения и записи")

Понятно, что текущий статус файла - некое число, отдельные биты которого сигнализируют об установке (или отсутствии) некоторых флагов. Как показано в примере, поле, в котором хранится значение модификатора доступа, можно вырезать с помощью специальной маски O_ACCMODE, определенной в fcntl.h.

При запуске новой программы ОС автоматически открывает три дескриптора файла, которые называются стандартным вводом, стандартным выводом и стандартным выводом диагностики соответственно. Они всегда имеют значения 0, 1 и 2. Не спутай stdin, stdout & stderr с чем-нибудь другим из стандартной билиотеки ввода\вывода.

По умолчанию использование системного вызова Read на стандартном вводе приведет к чтению с клавиатуры, запись в стандартный вывод или вывод диагностики приведут к выводу информации на экран терминала. Как ты понимаешь, такого может и не быть :).

Qt Assistent: с документацией у нас тоже все, в порядке :-)

Системные вызовы ввода\вывода являются основой всей системы ввода\вывода *nix, но они примитивны и предоставляют возможность работы с данными в виде простой последовательности байт, что не всегда может быть удобно для программиста, потому что заставляет его задумываться над многими вещами. Хочу напомнить тебе о стандартной библиотеке ввода\вывода, описанной в stdio.h и содержащей намного больше средств (fprintf, getc, putc, etc), нежели упомянутые системные вызовы.

В *nix с каждым процессом связана маска создания файла, которая используется для автоматического выключения заданных битов прав доступа при создании новых файлов. Это бывает полезно для защиты от случайного включения "ненужных" прав доступа. В терминах языка C, если счи- тать, что маска задана в целочисленной переменной Mask, то реальные права доступа будут получены следующим выражением: (~mask) & mode.

Для изменения маски создания файла существует системный вызов Umask, принимающий единственный параметр типа mode_t (который в оче- редной раз оказывается обычным це-

лым числом). Например, вызов umask(022) запрещает вновь созданным файлам текущего процесса присвоение файлу прав доступа на запись. Всем, кроме владельца.

Раз речь зашла о правах доступа, и теперь стоит упомянуть такой системный вызов, как Access, который определяет, может ли процесс полу- чить доступ к файлу в соответствии с истинным (а не с действующим) идентификатором пользователя и группы. И еще один системный вызов - Chmod. Здесь комментарии излишни.

В *nix один файл может иметь несколько имен. То есть существует возможность связать одну и ту же последовательность данных с несколькими именами, а создавать копии файла не нужно. Такое имя называется жесткой ссылкой, а количество таких ссылок, связанных с файлом, - счетчик ссылок. Для добавления нового имени используется системный вызов Link (const char *original, const char *link), а для удаления - Unlink (char *name), который просто удаляет указанное имя и уменьшает счетчик ссылок на единицу. Сами же данные будут безвозвратно потеряны только в том случае, если этот счетчик равен

 

 

 

KDevelop

 

Небольшой скрин RHIDE. Может, кто-нибудь найдет что-то знакомое :-)

 

 

 

ХАКЕРСПЕЦ 02(51) 2005

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Создаем UI с помощью Qt Designer

нулю и если указанный файл не открыт для чтения ни в одной программе. Замечу, что для создания символьных ссылок используется системный вызов Symlink, описанный в unistd.h.

МНОГОЗАДАЧНОСТЬ

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

Основным примитивом, создающим процесс в *nix-системах, является системный вызов Fork() - фактически в нем и заключается вся многозадач- ность ОС. После успешного вызова этой функции ядро создаст новый, почти идентичный текущему процесс - дочерний. Оба процесса будут выполняться одновременно, продолжая свое выполнение с оператора, следующего за Fork(). Как различить эти два процесса? Если функция возвращает 0, значит, ты добрался до про- цесса-потомка. Если возвращаемое число > 0, то ты застрял на родительском. Иначе - системный вызов завершился с ошибкой, которую нужно анализировать.

Следующим системным вызовом, который необходимо упомянуть -

Execve, а точнее целое семейство вызовов, которые в итоге сводятся к одному, упомянутому мной. Выполняемая функция данного множества системных вызовов одна - загрузка новой программы в пространство памяти процесса. После одного из таких вызовов ни одного оператора, следующего за ним, выполнено не будет. Конечно, если и сюда ошибка не добралась своими грязными руками.

Кроме процессов существует еще один вид программной сущности - потоки. Что-то вроде облегченных процессов, выполняющихся в одном адресном пространстве. Примитивов работы с ними немало, и для каждой системы они свои. Однако любая POSIX-система включает в себя реализацию Posix-threads. Пару слов о ней: в ОС есть набор функций, описанных в pthread.h и называющихся pthread_*. Например, pthread_create() создает новый поток, возвращая его идентификатор. Конечно, одним из параметров этой функции будет указатель на функцию, которая станет новым потоком и начнет свое выполнение. Функция Pthread_cancel может попытаться завершить поток, а Pthread_exit будет являться аналогом обычного Exit для процесса.

Работаем с gdb

81

NB: после создания нового потока он сам (новый поток) и процесс, породивший его, начнут выполняться параллельно. И кто их знает, кто завершится первым. Для этого и существует функция Pthread_join, которая ждет завершения определенного потока и заодно запоминает значение, которое он вернул по завершению.

Все примеры использования этих функций ты найдешь в соответствующих man'ах. Главное не испугаться

èзаглянуть в них: все очень просто! Стоит только внимательно прочитать

èодин раз правильно применить полученную информацию.

TURN OFF

К моего большому сожалению, не могу подробно описывать все аспекты программирования на C под *nix, но я постарался упомянуть ключевые слова

èнаправления, по которым будет устроен дальнейший поиск информации. Кроме man'ов, я очень советую тебе посетить www.tldp.org, в котором огромное количество самой разной интересной информации по Linux. Первым делом советую заглянуть в NCurses programming guide, описывающую работу с библиотекой Ncurses, позволяющей гораздо более удобно взаимодействовать с терминалом и создавать текстовый пользовательский интерфейс. Далее я бы порекомендовал почитать про *unix IPC, межпроцессорное взаимодействие - очереди сообщений, семафоры и пайпы.

Если же не хочешь заморачиваться с ворохом всех этих системных вызовов и библиотек, всяких там файлов

èтерминалов, а желание быстро, легко и не отвлекаясь на уточнение тонкостей писать программы есть - читай про такие библиотеки, как Qt, GTK и т.д., которые вдобавок позволят использовать графический интерфейс. Окошки там всякие, кнопочки.

Âобщем, надеюсь, своим повествованием не отбил у тебя интерес к этой теме. E

Linux Programming Guide (www.tldp.org/LDP/lpg)

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

 

 

* N I X

 

 

Основным примитивом, создающим процесс в *nixсистемах, является системный вызов Fork() - факти- чески в нем и заключается вся многозадачность ОС.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

82 CODING ШЕЛЛДЛЯКОДЕРА

Андрей Семенюченко (semu@rbcmail.ru)

ШЕЛЛ ДЛЯ КОДЕРА

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

* N I X Á Å Ç

ПРОГРАММИРУЕМ НА BASH. РАЗБОР РЕАЛЬНОГО СЦЕНАРИЯ

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

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

 

ß

зыки сценариев полез-

 

ны для пользователя и

 

 

 

просто жизненно необ-

 

 

 

 

ходимы для любого

 

 

 

системного админист-

ратора. *nix-системы имеют множество встроенных и прикладных языков программирования. Наиболее популярными и часто используемыми из них являются Perl, Tcl, а также shell.

Сейчас ты, наверное, подумал: "Ха, да ведь шелл - это же командная оболочка, являющаяся как бы посредником между человеком и системой для упрощения взаимодействия". Совершенно верно, но не только! Это еще и мощное средство программирования. Плюсы использования интерпретируемых языков программирования оче- видны. Вот только некоторые из них.

1.Переносимость: ты можешь легко залить свой только что испеченный скрипт с машины, на которой установлена твоя любимая Fedore Core, на любую другую платформу под управлением, скажем, FreeBsd или Solaris. Главное, чтобы в системе был установлен интерпретатор для языка, на котором написан крипт.

2.Простота написания кода: нет необходимости специально обучаться сложному программированию на компилирующих языках, таких как С, С++, Pascal, Fortran. Такое программирование наиболее очевидно, поскольку программа пишется в пошаговом режиме, то есть человек принимает решение о своем следующем шаге в зависимости от реакции системы на предыдущий шаг.

3.Быстрота написания кода: благодаря простоте синтаксиса и отладки ты сэкономишь много времени.

4.Большие функциональные возможности: хотя интерпретируемые языки и нельзя сравнить по своей функциональности, например, с С, тем не менее, не нужно недооценивать всей их мощи.

ПРОГРАММИРОВАНИЕ НА SHELL

Давай рассмотрим программирование на shell более подробно. Поскольку у тебя на Linux определенно

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

Нет ничего страшного, если в каче- стве оболочки ты используешь sh. Возможно также, что у тебя установлен Korn Shell (ksh) или что-то еще, тогда тебе нужно всего лишь придерживаться стандарта POSIX, если хо- чешь, чтобы твои shell-сценарии могли быть интерпретированы другим шеллом. Пройдя по ссылке www.unix.org.ua/orelly/unix/ksh/appa_02.htm, ты сможешь прочитать статью о IEEE 1003.2 POSIX shell стандарте и его поддержке в Korn shell. Дополнительные же преимущества bash опишу чуть позже.

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

Обычно все сценарии начинаются с одной из следующих строк или набора строк:

#!/bin/sh

#!/bin/bash

#!/usr/bin/perl

#!/usr/bin/tcl #!/bin/sed -f #!/usr/awk -f

Ты, наверное, уже заметил, что каждая строка начинается одинаково, с символов "#!". Эти строки объясняют системе, что запущенный файл, - это не что иное, как сценарий, и его следует обработать с помощью указанного после символов "#!" интерпретатора.

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

ñhmod 700 my_script_name.sh

èëè

chmod u+rwx my_script_name.sh

IEEE 1003.2 POSIX shell стандарт

ХАКЕРСПЕЦ 02(51) 2005

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Список сценариев в /etc/rc.d/init.d

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

sh my_script_name bash my_script_name

ОТ ТЕОРИИ К ПРАКТИКЕ

Я думаю, наступил момент рассмотреть какой-нибудь пример практического использования скрипта, из которого сразу все станет ясно. Но перед этим хочу обратить твое внимание на то, что некоторую полезную роль в написании кода играют редакторы. Современные редакторы имеют уйму разных функций от подсветки кода до вставки в текст некоторых несложных конструкций. Все это на любителя. Ты можешь использовать vi или emacs, а мне хватает встроенного в Midnight comander редактора с подсветкой синтаксиса. Ну а выбор, как всегда, за тобой. Определись, что тебе больше нравится, и забудь.

Чтобы далеко за примерами не ходить, я решил залогиниться на свой ALT Master 2.2 и взять первый попавшийся на глаза скрипт запуска одного из демонов. Такие скрипты, как известно, находятся в /etc/rc.d/init.d/. Первым в каталоге init.d оказался файл Anacron - сценарий запуска для одного очень популярного планировщика задач, похожего на всем известный демон cron. Anacron также может периодически запускать команды в назначенное время, и в отличие от cron, нет необходимости постоянной работы системы (но это уже совсем другая история).

Разберем файл построчно. Как мы видим, в начале файла используется до боли знакомая конструкция, начи- нающаяся с "#!". Ты уже знаешь, на что она указывает системе. Далее следуют комментарии, которые предваряются символом "#". А вот тут уже становится интересно: появилась ка- кая-то строка, да еще с точкой в нача- ле. Вот она:

. /etc/init.d/functions

На самом деле ничего странного здесь нет. Символ "." является экви-

валентом команды source. Внутри сценария команда source other_file_name подключает файл other_file_name.

Она очень напоминает директиву препроцессора языка C/C++ - "#include". Коротко пробегись по включенному файлу и получи представление о том, что же представляет собой скрипт functions. На самом деле все становится предельно ясно с комментариями к файлу. Этот сценарий содержит функции, наиболее часто используемые скриптами автозапуска из /etc/init.d. Дальше в файле как раз встречаются функции, которые очень часто можно найти в скриптах.

Но вернемся к нашему сценарию автозапуска anacron.

[ -f /usr/sbin/anacron ] || exit

В данной строке мы видим опять же эквивалент команды Test. Как понятно из названия, она проверяет условие, которое в этом случае заключено в квадратные скобки. Ключ -f задается для проверки существования файла. Таким образом, данный блок операторов служит для того, чтобы точно знать, существует ли файл демона /usr/sbin/anacron, и только в этом слу- чае продолжать выполнение скрипта,

àиначе выйти вон.

Далее следует инициализация пере-

менных LOCKFILE и RETVAL, которая происходит при присвоении им определенных значений. Пока для нас эти переменные ничего не значат. При программировании на shell переменные не имеют типа, но в зависимости от того, какое значение им присвоено, возможна, например, целочисленная арифметика с переменными. После того как переменной присвоено зна- чение, ее можно использовать в каче- стве подстановки, приписав в начале ее имени символ "$". И помни разницу между именем переменной (RETVAL) и ее значением ($RETVAL): если, например, посмотреть в самый конец рассматриваемого скрипта, обнаружишь строку exit $RETVAL. Здесь используется оператор exit для завершения программы, который тоже возвращает значение переменной RETVAL.

83

Ну вот мы и добрались до начинки файла - объявления функций start(), stop() и restart(). Под их контроль как раз и попадает обработка параметров, поступающих скрипту от пользователя или других программ. Как понятно из названий, каждая функция производит соответственно запуск, останов или restart демона. В принципе, здесь все понятно. Интересно то, что дальше в функциях встречаются не совсем логичные переменные $?, $$, $PPID. Ничего подобного не объявлялось, тогда откуда они взялись? Сейчас все станет ясно. Дело в том, что существует специальный тип переменных - так называемые переменные окружения. В рамках любого процесса есть некоторое окружение, то есть набор переменных, к которым он может обращаться за получением определенных данных. Каждый раз, когда запускается командный интерпретатор, для него создаются переменные окружения. Эти переменные можно экспортировать любому дочернему процессу с помощью команды Export. Список переменных можно получить командой Set. Количество переменных окружения достаточно велико, поэтому в командной строке лучше дать команду set|more для того, чтобы иметь возможность пролистать весь список.

Так вот, переменная $? содержит значение последней выполнившейся команды. А переменная $$ таит в себе не что иное, как PID сценария, то есть идентификатор процесса сценария. Переменная $PPID - PPID, то есть родительский идентификатор процесса.

Получается вот что (сразу не скажу, что): внимательно посмотри на функцию Start().

daemon anacron -s

Командой Daemon пытаемся запустить файл демона anacron с опцией -s для синхронизации заданий. При удачном запуске команда Daemon вернет значение "0".

Уже известно, что переменная $? будет содержать код возврата пос- »

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

 

* N I X

 

Скачать tar.gz архив с исходниками bash любой версии, а также прочи- тать более подробную информацию ты можешь с сайта GNU Project www.gnu.org/s oftware/bash/b ash.html

Нужно учитывать, что строка #!/bin/sh на самом деле означает интерпретатор, использующийся в системе по умолчанию, которым в большинстве дистрибутивов Linux является bash.

А так выглядит файл при использовании xemacs

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

* N I X

 

 

 

 

 

 

 

При работе со строками в bash можно воспользоваться неинтерактивным строчным редактором sed и языком обработки шаблонов awk.

Определить версию bash, установленную у тебя, можно с помощью параметра --ver- sion.

84 CODING ШЕЛЛДЛЯКОДЕРА

ледней операции. Это значение и присваиваешь переменной RETVAL.

[ $RETVAL -eq 0 ] && touch "$LOCKFILE"

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

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

Функция restart() поочередно вызывает функции start() и stop(), чтобы перезапустить демон.

Ниже в файле расположен оператор выбора case, который выполняет тот или иной участок кода согласно заданным условиям. Иногда case называют блоком операторов, поскольку его можно представить в качестве большого количества операторов проверки условия if, then, else. В нашем случае проверяется значение переменной $1, которое представляет собой не что иное, как первый параметр, передающийся скрипту. Например, если в командной строке набрать anacron start, выполнится условие start, которое вызовет функцию start() и запустит демон. Блок case завершает ключевое слово esac.

ОТЛАДКА SHELL-СЦЕНАРИЕВ

Нужно признаться, что до выхода последней версии (bash 3.0) командный интерпретатор bash не имел своего отладчика и даже каких-либо отладочных команд, возможно, за исклю- чением команды Trap, которая устанавливает ловушки на сигналы, то есть определяет, какие действия нужно выполнить при получении сигнала. Формат команды Trap следующий:

trap [-lp] [arg] [sigspec ...]

Команда Arg выполняется при полу- чении командным интерпретатором указанных сигналов sigspec. Если указана опция -p, выдаются команды Trap, связанные с каждым из пере- численных сигналов. Опция -l приводит к выдаче списка имен сигналов и соответствующих им номеров. Сигнал можно задавать как по имени, определенному в файле <signal.h>, так и по номеру. Если в качестве сигнала указано DEBUG, команда Arg выполняется после каждой простой команды. Trap возвращает 0 в случае успеха, в противном случае -1.

Могут пригодиться некоторые команды, которые, казалось бы, к отладке не имеют никакого отношения. Например - команда Echo, которая умеет выводить значения переменных в процессе выполнения скрипта.

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

âуказанных точках сценария. Конечно же, ты помнишь, что скрипт

можно запустить строкой вида:

bash my_script_name

Если интерпретатору передать аргументы -n, -v или -x перед именем сценария, можно еще и получить некоторую полезную информацию. Ключ -n проверяет наличие синтакси- ческих ошибок не запуская сам скрипт, ключ -v выводит каждую команду до того как она будет выполнена, -x показывает результаты выполнения команд.

Например, если добавить любую некорректно сформированную строку в данный скрипт так, чтобы он не мог запуститься из-за синтаксической ошибки. Я просто добавил выражение "This is error for test" сразу после

Сценарий functions является вспомогательным контейнером с данными для других сценариев

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

df

 

 

n

 

o

 

КОД СЦЕНАРИЯ ANACRON

.

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

-x cha

 

e

 

 

 

 

 

 

 

 

 

 

#!/bin/sh

#Startup script for anacron

#chkconfig: 2345 41 59

#description: Run cron jobs that were left out due to downtime

#Source function library.

. /etc/init.d/functions

[ -f /usr/sbin/anacron ] || exit

LOCKFILE=/var/lock/subsys/anacron

RETVAL=0

start() {

echo -n "Starting anacron: " daemon anacron -s RETVAL=$?

[ $RETVAL -eq 0 ] && touch "$LOCKFILE" echo

}

stop() {

echo -n "Shutting down anacron: " rm -f /var/run/anacron.pid

if [ -n "`pidof -o $$ -o $PPID -o %PPID -x anacron`" ]; then

killproc anacron else

success "anacron shutdown"

fi RETVAL=$?

[ $RETVAL -eq 0 ] && rm -f "$LOCKFILE" echo

}

restart()

{

stop start

}

# See how we were called. case "$1" in

start) start

;;

stop) stop

;;

reload|restart) restart

;;

condstop)

if [ -e "$LOCKFILE" ]; then stop

fi

;;

condrestart)

if [ -e "$LOCKFILE" ]; then restart

fi

;;

status)

status anacron RETVAL=$?

;;

*)

echo "Usage: ${0##*/} {start|stop|reload| restart|condstop|condrestart|status}"

RETVAL=1

esac

exit $RETVA

ХАКЕРСПЕЦ 02(51) 2005

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

 

 

 

w

 

df

 

 

n

 

 

o

 

BASH 3.0 - ДВА ГОДА СПУСТЯ

 

.

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

-xcha

 

e

 

 

 

 

 

 

 

 

 

 

 

 

Почти два года прошло после выхода предыдущей версии bash (2.0). Видимо, разработчики зря времени не теряли: в недавно вышедшей версии bash 3.0 появилось много чего нового. Исправлены многочисленные ошибки, улучшена поддержка многобайтовых символов, устранены некоторые несовместимости с POSIX, интегрирована возможность интернационализации сообщений и отлад- чик bash debugger.

Вот только неполный список нововведений в bash 3.0:

-расширение ANSI. Появилась возможность задания escape-пос- ледовательности в шестнадцатеричном виде \x{hexdigits};

-новая переменная COMP_WORDBREAKS, которая содержит набор символов для разделения слов;

-изменение формата записи символов в значении переменной HISTCONTROL;

-поддержка многобайтовых символов с появлением нового аргумента --enable-multibyte, который нужно указать для configure при установки bash;

-новые переменные для реализации встроенного отладчика bash: BASH_ARGC, BASH_ARGV, BASH_SOURCE, BASH_LINENO, ASH_SUBSHELL, BASH_EXECUTION_STRING, BASH_COMMAND;

-для операторов for, case, select, arithmetic commands теперь хранится специальная информация, используемая для отладки;

-новая ловушка RETURN, используемая при возвращении функции;

-новая опция bash для так называемой внешней отладки - debugger;

-добавлены операторы для упрощения и оптимизации применения регулярных выражений;

-интегрированы пакет Gettext и библиотека Libintl для перевода сообщений шелла на различные языки.

Полный перечень исправлений и новых функций ищи здесь: http://cnswww.cns.cwru.edu/~chet/bash/NEWS

объявления функции start(). Теперь запустим его следующим образом:

bash -x anacron

В результате получили результаты выполнения команд, а также сообщение о синтаксической ошибке в строке ¹15 сценария.

ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ BASH

На самом деле возможности Bash сильно отличаются от умений многих других интерпретаторов, именно поэтому этот интерпретатор в настоящее время стал стандартом де-факто в Linux-системах. Другим не менее распространенным шеллом является sh, который по умолчанию поставляется

Результат выполнения команды bash -x anacron

85

Файлы, используемые для настройки и работы bash

со всеми системными дистрибутивами. Но по удобству использования и по функциональности sh сильно уступает bash, поэтому последний набирает все больше голосов как среди программистов и администраторов, так и среди рядовых пользователей. Ниже приведен список (далеко не полный!) возможностей, имеющихся у bash 2.0

èотсутствующих у sh:

-наличие оператора выбора select;

-зарезервированное слово function для оформления функций;

-ведение истории команд;

-специальный синтаксис оператора цикла for для использования совместно с арифметическими операциями: for ((expr1 ; expr2; expr3 )); do list; done;

-перенаправление вывода: <>, &>, >|;

-режим posix для изменения поведения команд согласно стандарту;

-расширение регулярных выражений для выполнения действий с подстроками (${p%[%]w}, ${p#[#]w});

-ловушка DEBUG trap;

-ловушка ERR trap;

-egrep-подобное расширение для поиска значения по образцу;

-возможность поиска без учета регистра;

-перенаправление в /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr,

/dev/tcp/host/port,

/dev/udp/host/port

Кроме того, bash имеет большое количество полезных переменных окружения: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID и т.п.

ПОДВОДИМ ИТОГИ

Как всегда после любой работы, нужно собрать урожай. А его немало: подробно рассмотрели код сценария автозапуска демона-планировщика anacron, убедились в силе и простоте программирования на скриптовых языках, узнали о нововведениях в bash 3.0 и об отладке только что написанного скрипта даже при отсутствии специальных возможностей отладки в старых версиях bash. Надеюсь, теперь ты избавился от фобии правки кодов имеющихся скриптов и даже сам можешь сварганить нечто подобное без особых проблем. Удачи! E

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

 

 

* N I X

 

 

В редакторе xemacs (emacs под X-Windows), помимо удобных средств редактирования, присутствуют также дополнительные средства отладки сценариев.

Опция -posix изменяет поведение bash в соответствии со стандартом 1003.2.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

* N I X

 

 

 

 

 

 

 

86 CODING ÈÇWINDOWS Â*NIX

Крис Касперски ака мыщъх

ÈÇ WINDOWS Â *NIX

ПОСОБИЕ ПО ПОРТИРОВАНИЮ ПРИЛОЖЕНИЙ

Ïоследнее время много разговоров о переносе *nix-программ на Windows. Только так, но никак не иначе. А ведь существует большое количество Windows-программ, аналога которым на других платформах не существует

(прежде всего это твои собственные программы). Стоит ли их переносить на *nix, и если да, то как?

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

 

»

…задачи, решаемые с

 

помощью компьютера,

 

 

 

нередко самим компью-

 

 

 

 

тером и порождаются.

 

 

 

Ïîë Ãðýì

Абсолютного переносимого программного обеспечения не существует, как не существует абсолютного нуля. Понятие "переносимость" еще не означает, что портирование сводится к простой перекомпиляции. Всегда требуются дополнительные усилия по его адаптации. Иногда эти усилия настолько значительны, что проще переписать программу с нуля, чем гонять ее между платформами. Систем- но-ориентированные пакеты (FAR, soft-ice) переносить вообще бессмысленно.

В любом случае ты должен полностью разобраться в исходных текстах, которые переносишь. При доминирующем стиле кодирования интерфейс программы перемешан с "вы- числительной" частью (спасибо визуальными средам разработки!), и разделить их не проще, чем сиамских близнецов (но разделять все же придется). Типичный код нашпигован большим количеством системно-зави- симых функций: вместо стандартных библиотечных функций преобладают вызовы API и MFC. Активно используются ассемблерные вставки и повсеместно - умолчания компилятора. Это в Borland'е char по умолчанию unsigned, а в других компиляторах он ведет себя совсем не так! Про "умол- чанную" кратность выравнивания структур я вообще молчу. Хуже только нестандартные расширения компилятора и специфические особенности его поведения. Большинство программ, созданных современными "программистами", не компилируются MS VC, если написаны на BCC и, соответственно, наоборот. До переноса на *nix им так же далеко, как их авторам до звания "программиста" (необязательно даже "почетного программиста", можно просто "стажера", путающего язык со средой разработки).

Считается, что перенос сокращает издержки на развитие и сопровожде-

ние проекта. Имея независимые версии для Windows и *nix, ты вынужден вносить исправления и гонять баги в обеих программах одновременно.

Портабельный код этих недостатков лишен. Якобы. Скажи, когда-нибудь ты пробовал писать программу, компилируемую более чем одним компилятором? Ругался при этом? И правильно! Я бы тоже ругался. Ограниче- ния, налагаемые переносимым кодом, лишают нас многих возможностей языка и значительно увеличивают трудоемкость разработки. Допустим, ты используешь шаблоны (Templates), и на MS VC все работает, но при переходе на другой компилятор программа разваливается к черту. А некоторые компиляторы не инициализируют статические экземпляры класса. Ну не инициализируют и все тут! Забудь о стандартах. Компиляторы все равно их не придерживаются.

При каждом внесении изменений в программу прогоняй ее через все целевые компиляторы. Код, специфичный для данной платформы, заботливо окружи #ifdef или вынеси в отельный файл, ну и т.д. В конечном счете ты получишь все те же два независимых проекта, но тесно переплетенные друг с другом, причем внесение изменений в один из них дает непредсказуемый эффект в другом. Нет-нет, не подумай! Я вовсе не противник переносимого кода, просто не понимаю тех, для кого переносимость является целью, а не средством. Никто не спорит, что такие проекты, как Apache или GCC, должны изначально разрабатываться как переносимые (процент системно-независимого кода в них очень велик), но вот мелкую утварь типа почтового клиента лучше зата- чивать под индивидуальную плат-

форму, а при переходе на *nix переписывать заново.

СЛОИ АБСТРАГИРОВАНИЯ

Если нужно быстро перенести программу - воспользуйся WINE или Willows. Это бесплатно распространяемые имитаторы Windows, оборачивающие *nix-функции толстым слоем переходного кода, реализующего Win32 API и работающие на: Windows 9x/NT/2000/XP, Linux, FreeBSD, Solaris, а Willows еще и на QNX.

Обрати внимание: не эмуляторы, а именно имитаторы (WINE именно так и расшифровывается: Wine Is Not Emulator - это вам не эмулятор). Портируемая программа исполняется на "живом" процессоре практически без потерь в скорости. Во всяком случае реклама говорит именно так. А что реальная жизнь? При всей схожести *nix и Windows NT (их ядра наследуют общий набор концепций) они во многом различаются. В *nix есть замеча- тельная функция Fork, расщепляющая процесс напополам. В NT ее нет. Функциям CreateProcess/CreateThread далеко до Fork. И вот почему. Накладные расходы на расщепление процесса ничтожны, чего нельзя сказать о создании процесса/потока с нуля. Кстати, с потоками в Linux сплошной напряг; внутренние потоки представляют те же процессы, но только немного усложненные. Всегда заменяй CreateThread на Fork, когда это только возможно (процессы, в отличие от потоков, исполняются в различных адресных пространствах и могут обмениваться данными только че- рез IPC, например, так происходит с проецированными в память файлами). К тому же средства синхронизации потоков в Windows и *nix далеко не как две капли воды, а в Linux-син-

При каждом внесении изменений в программу прогоняй ее через все целевые компиляторы.

ХАКЕРСПЕЦ 01(50) 2005

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Windows-приложение, запущенное под WINE

хронизация не поддерживается вовсе

èреализуется внешними библиотеками. Все это делает отображение Win32 API на *nix-функции неоднозначным,

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

ностях о производительности можно не вспоминать).

Конструктивно большинство имитаторов состоят из двух основных компонентов: бинарного интерфейса (Binary Interface) и библиотеки разработчика (Library). Некоторые имитаторы (например, Willows) включают еще и уровень абстрагирования от платформы (Platform-abstraction Layer), что упрощает их перенос на

УСТАВШИМ ОТ "ПАСЬЯНСА" ПОСВЯЩАЕТСЯ

Для переноса игр и других графических приложений лучше всего подходит WineX, в настоящее время переименованный в Cedega, - коммерческая версия имитатора WINE от компании Transgaming, ориентированная на DirectX, Direct3D, OpenGL и прочие технологии этого уровня. Работает в Linux, Mac, PlayStation 2, XBox и Next Gen. Хочешь "поквакать" в Linux? Нет проблем! А еще можно "подумать" или погонять в Need-for-Speed. Список поддерживаемых игр очень и очень велик.

QUAKE 3 íà Linux

87

другие системы, но это уже детали реализации.

Бинарный интерфейс включает в себя win32-загрузчик, "переваривающий" PE-файлы и с максимальной точностью воссоздающий привычное для них окружение. Необходимость в перекомпиляции при этом отпадает, однако совместимость остается на очень низком уровне. Реально удается запустить лишь небольшое коли- чество офисных приложений типа Office, Acrobat или Photoshop. Системные утилиты, скорее всего, откажутся работать, и тут на помощь приходит библиотека - заголовочные файлы плюс lib-файл. Адаптировав приложение, можно компилировать его как в ELF (тогда необходимость иметь на машине установленный имитатор отпадает) или в PE. Красота!

В крайнем случае можно воспользоваться полноценным эмулятором PC - VMWare или Win4Lin, однако полезность этого решения сомнительна. Дело даже не в аппаратных требованиях (я вполне успешно гоняю VMWare на P-III 733), а в удобстве использования (точнее, его отсутствии). Достаточно сказать, что обмениваться данными с эмулятором придется через виртуальную локальную сеть, гоняя их в обе стороны, в хвост и в гриву.

ПЕРЕНОС ПРИЛОЖЕНИЙ, СОЗДАННЫХ В MICROSOFT VISUAL STUDIO

Компания Mainsoft (та самая, у которой свистнули исходные тексты Windows 2000) выпустила замеча- тельный продукт Visual MainWin, позволяющий писать код в Microsoft Visual Studio и тут же компилировать его под разные платформы (Windows, Linux, HP-UP, AXI, Solaris), причем количество поддерживаемых платформ постоянно растет.

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

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

 

* N I X

 

Как портируются приложения

 

Рабочая

Build-сервер

Áèíàðèêè

 

станция

 

Native

Исходный

разработчика

HP-UX

HP-UX

êîä ïîä

 

 

Visual

 

 

Windows

 

 

MainWin

 

Native

 

AIX

C++

Plug-in

AIX

 

 

 

 

Code

 

 

Native

 

 

Solaris

 

Visual Studio

Solaris

 

 

 

Windows PC

Linux

Native

 

Linux

 

 

 

 

 

Unix

 

 

Native

 

 

 

Windows

 

 

 

Binary

 

 

Портирование приложений под Visual WinMain, интегриро-

ванного в Microsoft Visual Studio

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Ï Ð Î Á Ë Å Ì

 

 

 

 

 

 

 

 

Á Å Ç

 

 

 

 

 

 

 

 

* N I X

 

 

 

 

 

 

 

88 CODING ÈÇWINDOWSÂ*NIX

участки (пускай программист сам решает, как он будет их исправлять!), и препроцессор, подготавливающий исходный код к последующей трансляции GCC (или любым другим *nix-ком- пилятором), и, конечно же, обширная библиотека функций, реализующая: а) Windows-примитивы (SEH, DLL, процессы/потоки, средства их синхронизации, реестр, буфер обмена и поддержку национальных языков); б) графический и пользовательский интерфейс (GDI32, USER32); в) COM-модель (ActiveX, OLE, MIDL, DCOM); г) библиотеку времени исполнения (ALT, MFC, C Runtime library). Полный перечень на www.mainsoft.com/solutions/vmw5_wp.html.

Это коммерческий продукт, причем очень коммерческий (лицензия на одного разработчика стоит больше $2000), правда, доступна 30-дневная полнофункциональная демо-версия. Так что решай сам: нужно оно тебе или нет.

MainWin, конечно, мощная штука, но иногда требуется приложение помельче. Основной камень преткновения - это, конечно же, MFC. В Microsoft Visual Studio все визуальные средства разработки построены именно на нем. И хотя исходные тексты MFC доступны, перенести его на *nix-системы намного сложнее, чем создать с нуля, сохранив иерархию классов и прототипы функций.

wxWindows - это бесплатная библиотека, практически полностью совместимая с MFC и работающая во всех

класс

MFC класс

wxWindows класс

 

 

 

Document

CDocument

wxDocument

 

 

 

View

CView

wxView

 

 

 

Edit view

CEditView

отсутствует

 

 

 

Template class

CMultiDocTemplate

wxDocTemplate

 

 

 

MDI parent frame

CMDIFrameWnd

wxDocMDIParentFrame

 

 

 

MDI child frame

CMDIChildWnd

wxDocMDIChildFrame

 

 

 

Document manager

отсутствует

wxDocManager

 

 

 

Cоответствие основных классов между MFC и wxWindows

Так выглядит Visual WinMain

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

m

W W W

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

 

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x cha

 

 

 

 

WINE

Популярный имитатор Windows, поддерживающий большое количество UNIX-платформ. Бесплатен: www.winehq.org;

WinX, îí æå Cedega

Коммерческий вариант WINE, ориентированный на игры и работающий преимущественно на LINUX-платформе: www.transgaming.com;

CodeWeavers

Коммерческий имитатор Windows, работающий только на Linux и ориентированный на запуск офисных приложений: www.codeweavers.com;

Visual MainWin

Плагин к Microsoft Visual Studio, упрощающий создание переносимого кода и позволяющий компилировать Windows-прило- жения под различные платформы. Здесь же лежит пара статей по переносу критических бизнес-приложений: www.mainsoft.com/products/mainwin.html;

wxWindows

Кросс-платформенная библиотека, более или менее совместимая с MFC. Исходные тексты доступны, денег не просит: www.wxwindows.org;

LIBINT

Бесплатная библиотека для работы с INI-файлами на UNIX: http://libini.sourceforge.net;

Free Pascal

Бесплатный кросс-платформенный компилятор Pascal'а с ограниченной поддержкой Delphi: www.freepascal.org;

Porting MFC applications to Linux

Толковая статья про перенос MFC-приложений в UNIX при помощи wxWindows: www.106.ibm.com/developerworks/library/l-mfc;

*nix-системах, где есть GTK+, Motif или его бесплатный клон Lesstif. Единственное отличие заключается в том,

что вместо префикса "C" здесь используется "wx", в результате чего CWnd превращается в wxWnd. Некоторые классы еще не реализованы (например, отсутствует CEditView), а когда они появятся - неизвестно. Это, конечно, неприятно, но и не смертельно. Без недостающих классов можно какнибудь обойтись, заменив CEditVIew на wxTextCtrl, а операцию "перебивки" префиксов загнать в препроцессор или повесить на макрос. Самое главное - wxWindows прекрасно работает на Windows, а значит, один проект не распадется на два!

На сайте IBM есть замечательная статья по переносу MFC-приложений на wxWindows (см. врезку), а на сайте самой wxWindows еще немного материалов на эту тему. Судя по баннерам, проекту покровительствуют весьма влиятельные компании - VMWare и Helpware, поэтому за его дальнейшую судьбу можно не волноваться.

Множество полезных библиотек можно найти на www.sourceforge.net, например, библиотеку для работы с ini-фай- лами (не анализировать же ее с помощью Бизона!) - libini.lib. Все они

ХАКЕРСПЕЦ 01(50) 2005