Новые книги

Вниманию читателей предлагается справочник по PHP.

Справочник предназначается для людей, уже освоивших азы программирования на языке PHP.

Справочник создан на основе информации, предоставленной на сайте «Справочник Web-языков» www.spravkaweb.ru.
В этом полном руководстве по C# 4.0 - языку программирования, разработанному специально для среды .NET, - детально рассмотрены все основные средства языка: типы данных, операторы, управляющие операторы, классы, интерфейсы, методы, делегаты, индексаторы, события, указатели, обобщения, коллекции, основные библиотеки классов, средства многопоточного программирования и директивы препроцессора. Подробно описаны новые возможности C#, в том числе PLINQ, библиотека TPL, динамический тип данных, а также именованные и необязательные аргументы. Это справочное пособие снабжено массой полезных советов авторитетного автора и сотнями примеров программ с комментариями, благодаря которым они становятся понятными любому читателю независимо от уровня его подготовки.

Книга рассчитана на широкий круг читателей, интересующихся программированием на C#.Введите сюда краткую аннотацию

ГЛАВА 7. Устройства и файловые системы



      ИМЯ: mntlook

mntlook Поиск файловых систем на устройствах

НАЗНАЧЕНИЕ

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

ФОРМАТ ВЫЗОВА

   mntlook    

ПРИМЕР ВЫЗОВА

   mntlook /dev/hd*Поиск файловых систем на всех жестких дисках    

ТЕКСТ ПРОГРАММЫ

       1   static char id[] =
         "@(#) mntlook v1.0 Look for mounts Author: Russ Sage";
                       Поиск файловых систем
       
       3   #include
       4   #include
       5   #include
       6   #include
       7   #include
       
       9   #define BSIZ 512
       
       11  main(argc,argv)
       12  int argc;
       13  char *argv[];
       14  {
       15      struct filsys sb;
       16      int d, dev;
       17      char buf[BSIZ];
       
       19      for (d = 1; d < argc; d++)
       20      {
       21          if (argv[d][0] == '-')
       22          {
       23              printf("mntlook: invalid argument %s\n", argv[d]);
       24              printf("usage: mntlook device [device ...]\n");
       25              continue;
       26          }
       27          if ((dev = open(argv[d],O_RDONLY)) < 0)
       28          {
       29              sprintf(buf, "cannot open %s",argv[d]);
                              невозможно открыть
       30              perror(buf);
       31              continue;
       32          }
       
       34          /* throw away first block */
               обойти первый блок
       35          if (read(dev, &sb, sizeof(sb)) == -1)
       36          {
       37              perror("cannot read block 0");
                        не читается блок 0
       38              continue;
       39          }
       
       41          /* block 1 is the superblock */
               блок 1 является суперблоком
       42          if (read(dev, &sb, sizeof(sb)) == -1)
       43          {
       44              perror("cannot read block 1");
                        не читается блок 1
       45              continue;
       46          }
       
       48          if (sb.s_magic == S_S3MAGIC)
       49          {
       50              printf("\nDEV: %s --> VALID file system\n",argv[d]);
       51              printf("filsys: %s\n",sb.s_fname);
       52              printf("pack  : %s\n",sb.s_fpack);
       53              printf("type  : %s byte block\n",
       54                     (sb.s_type == S_B512) ? "512" : "1024");
       55              printf("magic : %lx\n",sb.s_magic);
       56          }
       
       58          close(dev);
       59      }
       60  }    

ОПИСАНИЕ

Зачем нам нужна программа mntlook?

Файловые системы являются сердцевиной системы UNIX. Сама система не существует вне файловой системы, а расширенные возможности системы обеспечиваются файловой системой. Даже несмотря на то, что файловые системы настолько важны, UNIX не имеет никаких средств для обнаружения файловых систем как таковых. Не имеется даже средств, которые могли бы сообщить нам, какая информация находится в суперблоках. Нам необходимо универсальное средство для работы с файловыми системами. Оно должно обнаруживать и идентифицировать суперблоки, находящиеся на устройствах. Заметим, что операция открытия устройства обычно требует наличия привилегий суперпользователя.

Что делает mntlook?

Программа mntlook предназначена для просмотра содержимого файлов устройств и поиска суперблока. (Мы вкратце рассматривали суперблоки ранее). Когда суперблок обнаружен, из него извлекается и выводится на экран имя файловой системы, имя дискового пакета, используемый размер блока и идентификационный "магический номер". Первоначальной целью данной утилиты было обнаружение на внешнем носителе машины таких файловых систем, которые в настоящий момент не смонтированы. Но когда данная программа открывает и читает устройство, ей все равно, было ли устройство смонтировано или нет, поскольку доступ к нему выполняется на более низком уровне, чем уровень файловой системы. В результате обнаруживаются все файловые системы, независимо от того, были они смонтированы или нет. Давайте рассмотрим, каким образом файловые системы связаны с физическим носителем. К каждой машине подсоединено фиксированное число периферийных устройств. Для работы со сменными носителями в UNIX реализована концепция монтированного и немонтированного файлового пространства. Но первым шагом является установка пакета дисков (или гибкого диска) в дисковое устройство. После этого можно выполнять операции чтения и записи на физических носителях, указывая определенные имена устройств. Монтирование представляет собой логическое действие, которое читает суперблок с пакета дисков и записывает его в память, где ядро системы поддерживает свою версию суперблока. Периодически выполняется запись версии, находящейся в памяти, обратно на диск, чтобы эти две версии были по возможности одинаковыми. В System V это делает программа update, которая работает в фоновом режиме с момента загрузки системы. Для обращения непосредственно к физическому носителю используются такие команды, как, например, команда "od -c /dev /rfd0", которая дампирует неструктурированный гибкий диск. Одной из команд, которые непосредственно помещают данные на устройство, является команда "cp file /dev/rfd0". Область данных начинается с самого первого байта на гибком диске. Такие данные несовместимы с командами tar, cpio или файловой системой. Для обращения к файловой системе используется команда "mount /dev/fd0 /mnt". Начиная с этого момента, все обращения к данному устройству выполняются через каталог /mnt. Важно то, что непосредственный доступ к файлу устройства является операцией более низкого уровня, чем операции файловой системы, что позволяет прочитать информацию о суперблоке непосредственно с устройства. Входной информацией для программы mntlook являются имена файлов устройств. В командной строке нельзя указывать никакие опции. Имена устройств могут быть как блочными, так и символьными. Для операции чтения это не имеет никакого значения, если только у вас имеются права чтения. Затем программа читает второй блок и проверяет "магическое число", определяющее суперблок. Суперблок - это просто структура языка Си, которая предопределена системой и хранится в файле filsys.h, что указано в нашей программе оператором #include. Магическое число представляет собой длинное целое, имеющее заранее определенное значение. Если элемент структуры, которая прочитана с диска, содержит это число, то считается, что остальная часть структуры является корректными данными. Для каждой файловой системы имеется только одна структура суперблока. Если магическое число такое, как надо, выводится остальная информация о файловой системе. Если это число некорректно, на экран ничего не выводится и программа обрабатывает в цикле следующий файл устройства, указанный в командной строке. Данная программа может служить в качестве функции, обеспечивающей безопасность, поскольку она умеет идентифицировать файловые системы, которые кто-либо оставил на машине несмонтированными. Как отмечается в главе 9, нарушители защиты могут читать данные с немонтированных устройств, поэтому если оставить устройство или файловую систему немонтированными, то на самом деле это не предохраняет их от несанкционированного доступа.

ПРИМЕРЫ

   1.  $ mntlook /dev/hd13

Поиск суперблока на устройстве с именем hd13. Это имя указывает устройство 1, третий раздел. Для просмотра разделов в среде XENIX нужно запустить программу fdisk. Для System V нужно воспользоваться командой iv.

   2.  $ mntlook /dev/fd0*

Поиск файловых систем на гибких дисках с любой плотностью записи, находящихся в устройстве 0. Это снова пример для системы XENIX.

   3.  $ for DEV in /dev/*[fh]d*
   > do
   >        echo "checking device: $DEV"
   >        mntlook $DEV
   > done

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

ПОЯСНЕНИЯ

Строки 3-7 определяют включаемые файлы, которые использует данная программа. Вам необходимо изучить эти файлы, поскольку они не только помогут вам понять работу этой программы, но и покажут вам некоторые важные значения, имеющие отношение к файловым системам. Строка 9 определяет размер используемого буфера. Этот буфер применяется только для хранения сообщений об ошибках, поэтому он не должен быть очень большим. Строка 15 определяет структуру суперблока. Он имеет тип filesys (см. включаемый файл sys/types.h). На моей машине суперблок имеет размер 1024 байта. Если вы не знаете точно размер буфера у вас, то вы можете проверить его, вставив в программу следующий оператор:

    printf ("the size is %d",sizeof(sb))

Строка 16 описывает рабочую переменную d и дескриптор файла dev. Строка 17 объявляет буфер размером BSIZE. Строки 19-59 - это один большой цикл for. Этот цикл представляет собой всю остальную часть программы. Он выполняется столько раз, сколько аргументов указано в командной строке. Счетчик цикла начинается с 1, поскольку первым аргументом argv[0] является имя команды. В качестве аргументов должны быть указаны имена файлов, поэтому данный цикл использует каждое имя по очереди. В строках 21-26 проверяется, не начинается ли текущий рассматриваемый нами аргумент со знака '-'. Если да, то это опция, что представляет собой ошибку, поэтому выводится сообщение об ошибке и оператор continue вызывает выполнение следующей итерации цикла. Таким образом, данная программа отвергает опции, но работает при обнаружении имен файлов. Считая, что имя файла было найдено, строки 27-32 открывают файл устройства с этим именем только для чтения. Если данный вызов open неудачен, мы посылаем сообщение в буфер вместе с именем, указанным в командной строке. Этот буфер передается программе обработки ошибок (системной), которая использует наше сообщение как первую часть своего сообщения об ошибке. Она выводит системное сообщение, которое определяет данную ошибку. По оператору continue начинается выполнение следующей итерации цикла for. Строки 35-39 читают первый блок файла. Для корневой файловой системы первым блоком является загрузочная запись. Если при этом чтении возникает ошибка, выводится сообщение об ошибке и выполнение цикла продолжается. Строки 42-46 читают второй блок, который должен находиться в том месте, где размещается суперблок, если он имеется. По информации, прочитанной и помещенной в структуру, мы можем получить доступ к каждому элементу по его имени. Строка 48 проверяет, равно ли магическое число в структуре магическому числу, определенному в файле заголовка. Если они совпадают, программа mntlook выводит имя файла устройства и сообщение о том, что файловая система корректна, имя файловой системы (если оно имеется), имя пакета дисков, размер используемого блока и магическое число в шестнадцатиричном виде. В строках 53-54 мы имеем подобие кодированной структуры: оператор printf использует структуру типа if-then-else для указания строки, которую нужно выводить. После того как выведена первая строка, выполняется проверка и если она прошла успешно, то выводится значение 512. Если в результате проверки получено значение "ложь", выводится значение 1024. Этот метод описан в книге B.W.Kernighan, D.M.Ritchie "The C Programming Language" (Prentice-Hall, 1978). Строка 58 закрывает устройство, и цикл возвращается в начало для принятия следующего имени устройства.

РАЗМЕРНЫЕ ПАРАМЕТРЫ

Теперь, когда мы рассмотрели взаимоотношения между устройствами и файловыми системами и некоторые параметры, связанные с форматами дисков, давайте обратимся к гайкам и болтикам этих устройств. Хотя основная часть этой информации может показаться экзотичной, она может оказаться важной при определенных обстоятельствах. Например, для установки системы UNIX на новую машину вам нужно разбить диск на сегменты и понимать, каким образом UNIX фактически располагается на диске. Если вы создаете программы, которые выполняют какую-либо операцию низкого уровня с диском, вам, очевидно, необходимо понимать, что вы делаете. Администраторам, поскольку они должны добавлять новые устройства в систему, необходимо уметь определять количество файловых систем (т.е. сколько можно создать разделов на диске), их размеры и знать, каким образом установить файловые системы в эти разделы. Администраторы должны также уметь писать или модифицировать драйверы устройств. Наконец, при работе с дисками возникают проблемы, такие как плохие блоки, которые необходимо изолировать и с которыми приходится иметь дело.

РАЗМЕРЫ БЛОКОВ

System V является последним достижением ветви фирмы AT&T в фамильном дереве UNIX. Это означает, что System V содержит последние правки, внесенные в исходную систему UNIX. Эти правки предназначены для того, чтобы сделать UNIX жизнеспособным и стойким коммерческим продуктом. Для повышения устойчивости были внесены изменения, касающиеся работы с файлами и размеров их блоков. Обычно обмен данными с дисками осуществляется блоками по 512 байтов. Дисковая аппаратура имеет дело именно с таким размером. Для учета этого факта UNIX первоначально использовал 512-байтные блоки внутри файловой системы, что, возможно, облегчало написание программ и создавало впечатление, что так и нужно. Однако нельзя отрицать, что при этом UNIX может работать медленно! Для ускорения работы внутренние программы в настоящее время используют блоки размером 1024 байта. Сам диск должен выполнить два обращения к 512-байтным блокам, но в системе две эти операции чтения рассматриваются как одна операция чтения блока размером 1024 байта. Единственная проблема заключается в том, что одни утилиты выдают результаты в 512-байтных блоках, а другие - в 1024-байтных, в зависимости от того, когда они были написаны. Когда сильно приближаются пределы свободного пространства на диске, вам действительно нужно знать, с каким размером вы имеете дело. Для лучшего понимания проблемы размеров блоков, в табл. 7-3 показано, какие утилиты какой размер блока используют. Эта информация получена в основном из System V на машине VAX, из другого варианта System V и из XENIX. Эти значения могут отличаться на разных машинах, но идея сохраняется. Вы видите, что большинство утилит выдают результат в блоках размером 512 байтов, но утилиты, относящиеся к файловой системе, выдают результат в 1024-байтных блоках. Поскольку UNIX обращается к дисковому пространству поблочно, важно уметь точно вычислять, сколько свободного пространства в файловой системе. Весьма плоха ситуация, когда имеется какой-то большой файл в редакторе vi (который использует файл /tmp для промежуточного редактирования), а на диске недостаточно места для записи временного файла редактора vi в реальный файл на диске. На самом деле это может случиться на персональных машинах с ограниченным (скажем, 20 Мбайт) объемом жесткого диска.

Таблица 7-3
Размеры блоков для различных команд системы UNIX

512 байтов/блок 1024 байта/блок
ls -s fdisk (размеры разделов)
sum mkfs
cpio, df, du fsck

РАСЧЕТЫ, СВЯЗАННЫЕ С БЛОКАМИ

Еще одним важным вопросом, имеющим отношение к физическим устройствам и логическим файловым системам, является определение местонахождения определенного блока на жестком диске. Номер этого блока вычисляется по номерам цилиндра, дорожки и сектора. Знание номеров блоков становится важным, когда на диске появляется дефектное место. Это дефектное место отмечается номерами цилиндра и головки. Вам необходимо вычислить, какие блоки попадают в дефектную область и занести их номера в таблицу дефектных блоков. Обратная задача также важна. Если программа fsck начинает сообщать, что где-то появился дефектный блок, то каким образом мы можем узнать номера цилиндра, головки, сектора и т.д. для данного дефектного блока? Такое обратное вычисление сделать очень тяжело, если не невозможно. Во-первых, номер блока представляет собой произведение четырех чисел. Трудно узнать, какие именно эти числа. Кроме того, файловые системы могут использовать информацию вида база/смещение, поэтому блок номер 1 в файловой системе в действительности является блоком номер 1382 на диске. Определить, какого вида информация была использована в данном случае, тоже тяжело. Конкретные данные в следующем примере относятся к вполне определенной машине, но на других машинах используются подобные зависимости. Эти данные относятся к машине с жестким диском объемом 20 Мбайт с системами XENIX/DOS.

Характеристики устройства:

    1 диск    = 615 цилиндров, или 615 цилиндров/диск
    1 цилиндр = 4 головки (дорожки), или 4 головки/цилиндр

Промышленный стандарт:

    1 дорожка  = 17 секторов, или 17 секторов/дорожку
    1 сектор   = 512 байт, или 512 байт/сектор
    1 Кбайт    = 1024 байта = 2^10
    1 Мбайт    = 1024 килобайта = 2^20 = 1 048 576 байт

Характеристики устройства различны для разных устройств, но промышленный стандарт для числа секторов на дорожку и байтов на сектор остается одинаковым. В табл. 7-4 показаны примеры характеристик различных устройств.

Таблица 7-4
Размеры жестких дисков и их конфигурация

Число цилиндров Число головок Мегабайты
981 3 25
697 5 30
981 5 42
925 7 55
1024 8 71

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

  615 цил   4 дор   17 сек   512 байт
  ------- * ----- * ------ * -------- = 21 411 840 байт/диск
   1 диск   1 цил   1 дор     1 сек
   
  21411840 байт    1 мегабайт
  ------------- * ------------ = 20.4 мегабайта/диск
   1 диск      1048576 байт

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

     цилиндр, дорожка, сектор = физический сектор
     цилиндр, головка, байт   = блок

Эти две записи выражают в точности одно и то же. Когда вы используете запись вида цилиндр/дорожка/сектор, то в результате получаете физический сектор. Используя запись вида цилиндр/головка/байт, вы получаете в результате номер блока. Следует помнить, что ГОЛОВКА - это то же самое, что и ДОРОЖКА. Если вы это запомните, все остальное встанет на свое место. Ниже приводятся некоторые общие вычисления, которые часто всплывают, когда вы работаете с диском на низком уровне. Эти примеры в большей степени относятся к самому устройству, чем к системе UNIX. Однако после того, как вы поймете эту информацию о диске, вам будет легче понять, как работает UNIX на этом уровне. 1. Сколько дорожек имеет диск?

              615 цил   4 дор
     Решение: ------- * ----- = 2460 дор/диск
               1 диск   1 цил2. Сколько байт в дорожке?
              17 сек   512 байт
     Решение: ------ * -------- = 8704 байт/дор
               1 дор    1 сек3. Сколько дорожек в одном мегабайте?
              2460 дор   1 диск
     Решение: -------- * ------ = 123 дор/Мб
               1 диск    20 Мб4. Сколько цилиндров в одном мегабайте?
              1 цил   2460 дор
     Решение: ----- * -------- = 30 цил/Мб,
              4 дор    20 Мб
 
          615 цил   1 диск     123 дор
     или  ------- * -------- * ------- = 30 цил/Мб
           1 диск   2460 дор    1 Мб5. Дан цилиндр 47,  дорожка 2, сектор 4. 
Какой физический номер сектора?
    Решение:
    Сначала мы обращаем внимание на то, что вопрос касается секторов. 
    В качестве единиц измерения даны цилиндр,  дорожка и сектор. 
    Как перевести их в другие единицы?  Мы знаем,  что головки - 
    это то же  самое, что  и  дорожки,  поэтому  в  вычислениях 
    нужно использовать 4 головки вместо 4 дорожек: 
              4 дор   17 сек           17 сек
     47 цил * ----- * ------ + 2 дор * ------ + 4 сек =
              1 цил   1 дор             1 дор
     
            = 3196 сек       +         34 сек + 4 сек =
     
            = сектор 3234    

РАЗМЕРЫ ФАЙЛОВ

В основном при работе в системе UNIX мы считаем, что ее ресурсы безграничны. Например, мы не заботимся о том, что созданный файл получится "слишком большим", а это не так уж редко в персональных компьютерах на гибких дисках. Если же мы занимаемся сопровождением и администрированием системы UNIX, то мы должны быть готовы иметь дело с ситуациями, когда превышаются различные предельные значения системы. Всегда лучше исследовать эти вопросы заранее в некритичных ситуациях, поэтому давайте рассмотрим пределы размеров файлов и их смысл. Некоторые параметры "зашиты" в ядро системы при ее генерации. Одним из таких значений является максимальный размер файла. Он определяет наибольшее число блоков, которые может занимать файл. Этот параметр тесно связан с принятым в UNIX методом использования индексных дескрипторов файла (inodes). Это наборы указателей, среди которых первые десять указывают на блоки данных, следующий указывает на другую таблицу, следующий - на таблицу, указывающую на таблицу и т.д. Имеется еще одно ограничение размера файла, которое определено для каждого пользователя во время работы в системе - число ulimit (user limit - пользовательский предел). Это значение устанавливается в момент вашей регистрации в системе и представляет собой число блоков по 512 байт, которые вы можете записать в любой заданный файл. В shell'е имеется команда ulimit, которая при ее вызове без аргументов выводит это число. Эта же команда позволяет вам уменьшить ваше значение ulimit. Только суперпользователь (root) может УВЕЛИЧИТЬ значения ulimit. Побочным эффектом уменьшения значения ulimit является то, что вы не можете снова увеличить его до регистрационного значения. Значение ulimit остается таким же на все время работы вашего shell, поэтому для восстановления регистрационного значения вам необходимо выйти из системы, а затем снова зарегистрироваться. Еще одним интересным моментом является то, что если вы установите ваше значение ulimit равным 0, вы не сможете создать никакие файлы! Максимально допустимым размером файла в данном случае является нулевой, поэтому никакой файл не может быть создан. Это представляется достаточно резонным, однако существуют такие ситуации, когда файл нулевого размера МОЖЕТ существовать. Опять же, для восстановления вашего обычного значения ulimit необходимо выйти из системы, а затем снова зарегистрироваться. Как отмечалось ранее, увеличить значение ulimit может только суперпользователь. Эта процедура довольно проста. Сначала нужно увеличить значение ulimit командой ulimit, а затем запустить shell. Этот новый shell имеет новое значение ulimit. Если мы хотим, чтобы система загружалась с shell, имеющим большее значение ulimit, мы можем установить программу в inittab (таблице инициализации системы), чтобы эта операция выполнялась автоматически. Ниже приводится пример программы, которая изменяет значение ulimit и запускает shell с этим новым значением. Напомним, что эта программа может быть запущена только суперпользователем.

       1   #include
       2   #include
       
       4   main()
       5   {
       6       long v1, v2, v3, newlimit = 5120;
       
       8       v1 = (long)ulimit(UL_GFILLIM, 0L);
       9       v2 = (long)ulimit(UL_SFILLIM,newlimit);
       10      v3 = (long)ulimit(UL_GFILLIM, 0L);
       
       12      printf("v1: %ld     v2: %ld    ulim: %ld\n",v1,v2,v3);
       13      setuid(getuid());
       14      execl("/bin/sh","ulimit sh", 0);
       15  }

Значение ulimit является возвращаемым значением системного вызова ulimit. Первый вызов ulimit в строке 8 получает исходное значение по умолчанию. Это значение сохраняется в переменной v1. Вызов в строке 9 устанавливает новое значение ulimit равным значению переменной newlimit. Если этот вызов оканчивается неудачей, переменной v2 присваивается возвращаемое значение -1, и мы видим это по распечатке, которую выдает строка 12. Если вызов был успешным, возвращаемым значением является новое значение ulimit, и это мы тоже видим. Затем вызов в строке 10 получает это значение ulimit. Это или новое значение, или старое, в зависимости от того, была ли успешной попытка изменить ulimit. В строке 13 значение идентификатора текущего процесса устанавливается равным значению идентификатора пользователя, запустившего данный процесс. Это сработает только в том случае, если пользователь, запустивший данный shell, имеет более низкий идентификатор, чем сам процесс. Цель заключается в том, чтобы предоставить возможность обычным пользователям запускать данный процесс, давая им временно права суперпользователя. (Не оставляйте исходный текст этой программы в системе, поскольку кто-то может превратить ее в "лазейку" и перекомпилировать ее - в главе 9 мы увидим такого рода дыры в системе защиты.) Строка 14 запускает shell. Аргументом этого shell является строка "ulimit sh". Эта строка будет выведена на экран, если мы выполним команду "ps -ef". Данный shell имеет новое значение ulimit. Возможность изменить значение ulimit позволяет нам определить наибольший возможный размер файла. Создание одного или нескольких таких файлов максимального размера полезно в целях тестирования. Например, полезно выяснить, сколько данных может содержать гибкий диск без переполнения или что произойдет, когда система выйдет за пределы свободных блоков. Мы хотим понять, как ведет себя система в таких ситуациях.


      ИМЯ: umntsys    

НАЗНАЧЕНИЕ

Размонтирование всех файловых систем, смонтированных в данный момент.

ФОРМАТ ВЫЗОВА

   umntsys    

ПРИМЕР ВЫЗОВА

    umntsys     Размонтирует все смонтированные файловые системы    

ТЕКСТ ПРОГРАММЫ

       1   :
       2   # @(#)umntsys v1.0  Unmount all file systems  Author: Russ Sage
                        Размонтирование всех файловых систем
       
       4   if [ "$#" -gt 0 ]
       5     then  echo "umntsys: too many arguments" >&2
       6           echo "usage: umntsys"              >&2
       7           exit 1
       8   fi
       
       10  /etc/mount | sed -n -e '/^\/ /d' -e 's/^.* on \(.*\)
       read.*/umount \1/p' | sh -    

ОПИСАНИЕ

Зачем нам нужен командный файл umntsys?

Иногда возникают ситуации, когда вы как администратор хотели бы запустить систему в однопользовательском режиме. Например, вы хотите сменить или установить жесткие диски и вам нужно, чтобы никто не имел доступа к этому устройству, пока вы с ним работаете. Вам может также понадобиться запустить систему в минимальной конфигурации с целью локализации какой-то проблемы. Поскольку выполнение операций завершения работы системы и перезагрузки представляет собой довольно длительную процедуру, было бы лучше иметь способ сохранить систему работающей, но переключить в однопользовательский режим, а затем быстро перезапустить многопользовательский режим, чтобы свести к минимуму неудобства пользователей. Для того чтобы сделать это, нам нужно понять концепцию "уровней работы системы" и использовать их. Уровень работы (run level) в системе UNIX представляет собой состояние или конфигурацию, в которой может быть машина. Фактически это число, которое определяет, какие возможности системы включены или отключены и находится ли система в одноили многопользовательском режиме. Описание того, что происходит на каждом уровне работы системы, содержится в файле /etc/inittab. Обычно изменение уровня работы системы включает в себя переход от многопользовательского режима (например, уровень 6), к однопользовательскому режиму (уровень S). Одним из побочных эффектов перехода от многопользовательского режима к однопользовательскому является то, что все дополнительные файловые системы размонтируются. Единственной смонтированной файловой системой является корневая (определенная как /dev/root, /dev/hd0a и т.п.). Ее никогда нельзя размонтировать. Когда происходит переход обратно к многопользовательскому режиму, файловые системы обычно повторно монтируются с помощью файла /etc/rc. Мы можем эмулировать однопользовательский режим путем прекращения выполнения всех процессов в системе командой kill и размонтирования всех файловых систем. Командный файл umntsys предназначен для этой цели.

Что делает umntsys?

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

ПОЯСНЕНИЯ

Первым делом командный файл umntsys проверяет отсутствие аргументов в командой строке. Поскольку для него не существует опций, командная строка должна быть пустой. Если количество аргументов больше нуля, это ошибка, поэтому на стандартное устройство регистрации ошибок выводится сообщение об ошибке, и программа завершается. Вся работа выполняется в строке 10. Этот оператор похож на волшебное заклинание. Начинается он с выполнения обычной команды mount без аргументов. По умолчанию команда mount выводит таблицу с информацией обо всех каталогах и именах устройств монтированных файловых систем. Эта таблица выглядит примерно так:

    |
    |    / on /dev/hd0a read/write on Mon Jan 06 09:53:03 1986
    |    /tmp on /dev/hd01 read/write on Mon Jan 06 09:53:03 1986
    |    /usr on /dev/hd02 read/write on Mon Jan 06 09:53:03 1986
    |    /u1 on /dev/hd03 read/write on Mon Jan 06 09:53:03 1986
    |    /u2 on /dev/hd04 read/write on Mon Jan 06 09:53:03 1986
    |    /u3 on /dev/hd05 read/write on Mon Jan 06 09:53:03 1986
    |    /mnt on /dev/fd01 read/write on Mon Jan 06 09:54:41 1986
    |

Когда файловая система смонтирована, требуются и каталог, и имя устройства. Когда файловая система не смонтирована, используется только имя устройства. Нам нужно вырезать имена устройств из таблицы монтирования и вставить их в команду umount. Это делается с помощью команды sed. Команда sed начинает работать с опцией -n, которая подавляет выполняемый по умолчанию вывод на экран, поэтому ничего не выводится, пока мы не попросим. Мы можем использовать это в своих интересах, отфильтровывая ненужные нам строки. Первой коррекцией таблицы смонтированных файловых систем является избавление от записи о корневой файловой системе, поскольку мы бы не хотели пытаться ее размонтировать. Поскольку корневой файловой системе соответствует каталог "/", мы можем использовать его в качестве ключа. Выражение в операторе sed означает: "Искать с начала строки первый символ наклонной черты (поскольку этот символ имеет специальное значение, он экранирован обратной косой чертой) и пробел за ним. Когда наклонная черта найдена, удалить ее". Данный шаблон поиска соответствует только записи о корневой файловой системе. Следующая операция редактирования выполняется более замысловато. Она использует возможность группирования регулярных выражений и последующей ссылки на них по номеру, что вы уже видели в некоторых наших предыдущих командных файлах. Данный синтаксис (регулярное выражение) предназначен для группирования символов и последующей ссылки на них с помощью номера \n. Фокус в том, чтобы выделить только имя устройства и сгруппировать его, что и делает команда подстановки sed'а. Первое выражение означает: "От начала строки распознать любой символ, за которым следует любое количество любых символов, пробел и слово `on'; сгруппировать следующие символы вплоть до пробела, слово `read' и все символы после него". В результате всего этого выделяется имя устройства и помещается во временную переменную, чтобы впоследствии к ней можно было обратиться. Вторая часть подстановки создает новую строку взамен исходной. Эта строка состоит из слова "umount", пробела, затем группового выражения номер 1, которое представляет собой временную переменную, содержащую имя устройства. В результате всех этих действий таблица смонтированных файловых систем (за исключением записи о корневой системе) превращается в набор команд размонтирования с именами устройств в качестве аргументов. Полученный результат имеет примерно такой вид:

    |
    |    umount /dev/hd0a
    |    umount /dev/hd01
    |    umount /dev/hd02
    |    umount /dev/hd03
    |    umount /dev/hd04
    |    umount /dev/hd05
    |    umount /dev/fd01
    |

Теперь эти команды по конвейеру передаются другому shell ("sh -"). Символ "-" указывает shell, что свои команды он должен получать со стандартного ввода, а в данном случае это наши команды umount, переданные по конвейеру. Они размонтируют все файловые системы.


      ИМЯ: lrg

flrgf Создает файл максимально возможного размера

НАЗНАЧЕНИЕ

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

ФОРМАТ ВЫЗОВА

   lrgf    

ПРИМЕР ВЫЗОВА

    lrgf      Определение границы размера файла    

ТЕКСТ ПРОГРАММЫ

       1   char id[] =
         "@(#) lrgf v1.0 Create the largest file Author: Russ Sage
                    Создать файл максимального размера
       
       3   #include
       4   #include
       5   #include
       6   #include
       
       8   #define FSIZ 512
       9   #define BSIZ 1024
       
       11  long ulimit();
       12  char buf[BSIZ];
       
       14  main()
       15  {
       16      register int n, fd, bcnt;
       17      char file[FSIZ];
       
       19      for (bcnt=0; bcnt    

ОПИСАНИЕ

Зачем нам нужна программа lrgf?

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

Что делает lrgf?

Lrgf - это программа, которая создает файл максимально возможного размера. Выполняется это путем записи в файл до тех пор, пока команда записи не окончится неудачей. Это означает, что в данный файл больше нельзя записать данные, и он достиг границы. При вызове программа lrgf выводит сообщение, содержащее общее количество байтов, которое вы можете записать в файл. Это значение вычисляется по значению ulimit, поэтому оно разное для разных пользователей и зависит от shell, с которым пользователь сейчас работает. Затем у вас запрашивается имя файла. Вы можете указывать любое имя, для которого вы имеете права записи. Одним из способов проверки жесткого диска является запись одного из таких больших файлов в каждый раздел диска и затем проверка отдельных файловых систем. После запуска программы вы увидите строку с сообщением, которое постоянно обновляется. Оно содержит общее число записанных блоков и количество байтов, которое записывалось при каждой попытке записи. Программа lrgf записывает в файл каждый раз по 1024 байта. В зависимости от вашего значения ulimit количество байтов, дописываемых в конец файла, может не быть равным в точности 1 Кб. Выходное сообщение постоянно печатается в одной и той же строке, заменяя на экране старое значение. Это достигается путем вывода только символа возврата каретки, а не перевода строки. Когда программа не может больше записывать данные в файл, итоговое количество блоков выводится на экран. Это общее число блоков, записанных в файл.

ПРИМЕРЫ

   1.  $ lrgf
   /dev/rfd0

Ввод имени устройства в ответ на запрос имени файла, в который будет производиться запись. При этом программа lrgf выполняет последовательную запись на гибкий диск неструктурированных данных. Тем самым проверяется, распознает ли драйвер устройства переполнение гибкого диска. Это важно знать при работе с командой cpio, которая предполагает, что драйвер устройства сообщит об остановке и запросе следующей дискеты.

    2.  $ lrgf
    /usr/tmp/lrg

Создание файла в файловой системе /usr. Большинство систем XENIX используют каталог /usr как отдельную файловую систему, отличную от корневой. Созданием файла в каталоге /usr /tmp мы можем проверить положение дел в этой часто используемой файловой системе.

    3.  $ lrgf
    /tmp/lrg

В данном случае создаваемый файл займет место в корневой файловой системе (если вы не имеете каталога /tmp в вашей собственной файловой системе). Потребуется не слишком много таких файлов для заполнения всех свободных блоков в корневой файловой системе.

    4.  $ lrgf
         /mnt/lrg

Создание файла на гибком диске в предположении, что на гибком диске имеется файловая система и она смонтирована в каталог /mnt.

    5.  $ F=0
    $ while :
    > do
    >           echo -r "-->  Making file $F  <--"
    >           lrgf <<-!
    >           $F
    >           !
    >           echo
    >           F=`expr $F + 1`
    > done

Данный цикл запускает программу lrgf бесконечное число раз. Счетчиком является переменная F. Она должна быть предварительно установлена в нуль, чтобы shell рассматривал ее как число, а не как символьную строку. Сначала выводится сообщение, содержащее имя создаваемого файла. Первым именем файла является 0. Программа lrgf запускается, используя в качестве входных данных "данный документ" (т.е. сам командный файл). В качестве ответа на вопрос об имени файла используется значение $F. Значение переменной F увеличивается, и программа lrgf вызывается снова. Именами файлов являются 0, 1, 2 и т.д. Это продолжается до тех пор, пока не останется больше свободного места. Вряд ли вы будете пользоваться этим часто, но для тестирования это прекрасное средство заполнить все свободное пространство. Если вы хотите увидеть, что делает ваша система, когда исчерпаны свободные блоки, примените данный командный файл.

ПОЯСНЕНИЯ

Строки 3-6 включают все необходимые файлы заголовков. Эти файлы содержат определения и метки, необходимые данной программе. Строки 8 и 9 определяют размеры буфера для имен файлов и буфера для записи на диск. Значение BSIZ можно поднастроить, если программа работает слишком медленно. У вас может возникнуть желание увеличить BSIZ до 4096, чтобы производилось не так много операций записи. Строка 11 определяет возвращаемое значение системного вызова ulimit как длинное целое. Строка 12 резервирует буфер, который должен быть записан. Этот буфер находится вне основной части программы из-за ограничений на размер внутри функций. В основном блоке программы наибольшая область автоматической памяти, которую вы можете иметь, равна размеру вашего стека. Вы можете сделать по-другому, объявив данный буфер как статическую переменную в функции main. Мы решили вынести его за пределы функции main и не объявлять как статическую переменную. Строка 16 объявляет некоторые рабочие переменные. Заметим, что они помещаются в регистры. Это сделано для ускорения работы программы и получения более компактного объектного кода. Строка 17 резервирует буфер, в который вы вводите имя файла.

Строки 19 и 20 заполняют записываемый буфер символами "x", поэтому после создания файла мы можем их там увидеть. Строка 22 выводит значение ulimit для вашего процесса. Обратите внимание, что вызов ulimit возвращает количество блоков, поэтому мы должны умножить это число на 512. В результате мы получим общее количество байтов, которое может содержать файл. Строки 24-26 запрашивают имя файла, читают его и подготавливают экран для следующего сообщения. Строки 28-32 открывают файл с указанным именем для получения дескриптора файла. Файл открывается для записи и чтения, создается при необходимости и обрезается, если он уже существует. Если операция открытия файла заканчивается неудачей, выводится сообщение об ошибке, и программа завершается. Строки 34-42 выполняют запись. Цикл for бесконечен, поскольку в середине оператора нет проверки значения счетчика. Переменная bcnt постоянно увеличивается, пока выполняется запись. Строка 36 выполняет запись в файл. Если запись неудачна, выводится сообщение об ошибке и по оператору break осуществляется выход из цикла. Строка 41 выводит количество выполненных операций записи и количество записанных байтов. Обратите внимание, что данный оператор print содержит возврат каретки (\r), а не перевод строки. Это позволяет курсору оставаться в одной итемах. экране поверх старых значений. Экран не скроллируется, что удобно для наблюдения. Выполнение цикла продолжается до тех пор, пока системный вызов write не закончится неудачей и оператор break не прекратит цикл. Когда это происходит, выполнение продолжается со строки 43, которая печатает "end of program". Выполнение команды "ls -l" для записанного файла показывает, сколько байтов имеет файл максимального размера. Это количество должно совпадать с числом, которое сообщила вам программа lrgf. В данной главе представлена лишь небольшая часть возможных исследований внутренней работы файловых систем и устройств в UNIX. Некоторые из представленных программ могут быть неприменимы в вашей версии системы UNIX или в вашей конфигурации аппаратных средств или могут выглядеть в вашей системе иначе. Однако общие принципы сохраняются, и вы можете использовать рассмотренные средства в качестве основы для ваших собственных исследований.

Назад | Содержание | Вперед