Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

6.2.3. Поиск и настройка базовой системной информации

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

Системный вызов

uname
позволяет программе обнаружить информацию времени ее выполнения.

#include <sys/utsname.h>

int uname(struct utsname* unameBuf);

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

unameBuf
. При нормальном завершении структура, на которую он указывает, заполняется строками, завершаемыми
NULL
, которые описывают текущую систему. В табл. 6.1 представлены члены структуры
utsname
.

Таблица 6.1. Члены структуры

utsname

Член Описание
sysname
Название
операционной системы (в данном случае
Linux
).
release
Номер версии выполняющегося ядра. Это полная версия вроде
2.6.2
. Номер может быть легко изменен тем, кто выполнял сборку ядра, и вполне возможно, что цифр будет больше трех. Во многих версиях можно встретить дополнительную цифру для описания примененных исправлений, например,
2.4.17-23
.
version
Под Linux здесь содержится временная метка, описывающая время, когда собиралось ядро.
machine
Короткая строка, указывающая тип микропроцессора, на котором работает операционная система. Для Pentium Pro или более мощных она может быть
i686
, для процессоров класса Alpha —
alpha
, а для 64-разрядных процессоров PowerPC —
ррс64
.
nodename
Имя хоста машины, которое обычно является первичным именем хоста в Internet.
domainname
Домен NIS (или YP), которому принадлежит машина.

Член

nodename
(имя узла) часто называется системным именем хоста (то, что отображает команда
hostname
), однако его не следует путать с именем Internet-хоста. Несмотря на то что во многих системах эти члены не различаются, путать их не стоит. В системе с множеством Internet-адресов есть множество имен Internet-хостов, но только одно имя узла, поэтому эти имена не являются эквивалентными.

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

host127-56.raleigh.myisp.com
, а имена Internet-хостов меняются каждый раз при отключении на длительное время от модема [6] . Владельцы этих машин дают своим компьютерам имя узла, которое им больше нравится, например,
loren
или
eleanor
, что совершенно не относится к адресам Internet. При наличии множества машин, работающих на одном домашнем шлюзе, все они будут разделять один Internet-адрес (и одно имя Internet-хоста), но могут иметь имена вроде
Linux.mynetwork.org
и
freebsd.mynetwork.org
, которые все еще не являются именами Internet-хоста. В связи со всеми вышеперечисленными причинами, предполагать, что имя системного узла является допустимым именем Internet-хоста для машины не верно.

6

Большинство, но не все, поставщики услуг доступа в Internet назначают динамические IP-адреса, а не статические.

Имя узла системы устанавливается с помощью системного вызова

sethostname
[7] , и имя домена NIS (YP) [8] — посредством системного вызова
setdomainname
.

#include <unistd.h>

int sethostname(const char * name, size_t len);

int setdomainname(const char * name, size_t len);

Оба этих системных вызова принимают указатель на строку (не обязательно завершающуюся

NULL
), которая содержит подходящее имя, и целочисленный аргумент, указывающий размер строки.

7

Несмотря на имя, которое может ввести в заблуждение, этот системный вызов устанавливает имя узла, а не имя Internet-хоста машины.

8

Сетевые информационные службы (Network Information Services — NIS) предоставляют для машин в сети механизм совместного использования информации, такой как пользовательские имена и пароли. Ранее они назывались "желтыми страницами" (Yellow Pages — YP). Имя домена NIS — часть этого механизма, который реализуется за пределами ядра системы с тем исключением, что доменное имя хранится в структуре

utsname
.

6.3. Совместимость

Приложения, которые скомпилированы с заголовочными файлами из библиотеки

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

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

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

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

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

Большинство других библиотек поддерживают совместимость, включая номер версии в имя библиотеки и позволяя множеству разных версий быть установленными одновременно. Например, инструментальные наборы GTK+ 1.2 и GTK+ 2.0 могут быть одновременно установлены в одной системе, каждый со своим собственным набором заголовочных и библиотечных файлов, путем встраивания в путь к заголовочным файлам и файлам библиотек имени версии.

Раздел стандарта по наименованию разделяемых библиотек в Linux включает старший номер версии для возможности установки в системе множества версий библиотеки. Это используется не очень часто, поскольку в одной системе невозможно скомпоновать новые приложения с множеством версий библиотеки; это просто обеспечивает поддержку лишь обратной совместимости для существующих приложений, построенных на более старых системах. На практике разработчикам требуется собирать приложения со многими версиями одной и той же библиотеки, поэтому большинство основных библиотек содержат в своем названии и номер версии.

Глава 7

Средства отладки использования памяти

Несмотря на то что С бесспорно является стандартным языком программирования в системах Linux, он имеет ряд особенностей, не дающих программистам возможности писать код, не содержащий тонких ошибок, которые впоследствии очень сложно отладить. Утечки памяти (когда память, выделенная с помощью

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

7.1. Код, содержащий ошибки

 1: / * broken.с* /

 2:

 3: #include <stdlib.h>

 4: #include <stdio.h>

 5: #include <string.h>

 6:

 7: char global[5];

 8:

 9: int broken(void){

10: char *dyn;

11: char local[5];

12:

13: /* Для начала немного перезаписать буфер */

14: dyn = malloc(5);

15: strcpy(dyn, "12345");

16: printf ("1: %s\n", dyn);

17: free(dyn);

18:

19: /* Теперь перезаписать буфер изрядно */

20: dyn = malloc(5);

21: strcpy(dyn, "12345678");

22: printf("2: %s\n", dyn);

23:

24: /* Пройти перед началом выделенного с помощью malloc локального буфера */

25: * (dyn-1) ='\0';

26: printf ("3: %s\n", dyn);

27: /* обратите внимание, что указатель не освобожден! */

28:

29: /* Теперь двинуться после переменной local */

30: strcpy(local, "12345");

31: printf ("4: %s\n", local);

32: local[-1] = '\0';

33: printf("5: %s\n", local);

34:

35: /* Наконец, атаковать пространство данных global */

Поделиться с друзьями: