, то увидим прогрессирующее упрощение имен по мере продвижения к первой записи - устройству 0, которое имеет высокую плотность записи по умолчанию. Для того чтобы обратиться к нему как к устройству с низкой плотностью записи, необходимо использовать имя fd048, а не fd0. Поскольку большинство используемых гибких дисков име- ют низкую плотность записи, то имя fd048ds9 является умолчанием в программе mntf. Строка 17 соответствует опции -1 для указания устройства 1 вместо устройства 0. Строки 18-22 проверяют, сиществует ли каталог для монти- рования второго устройства. Если вы используете два гибких диска од- новременно, то вы не можете монтировать их оба в один и тот же ката- лог. Для разрешения этой проблемы программа mntf использует для монти- рования устройства 1 каталог /mnt1, а не /mnt. Если каталог /mnt1 не существует, по умолчанию используется каталог /mnt, и все хорошо, если вы используете только устройство 1. Однако следует избегать монтирова- ния одного гибкого диска на место второго. Вы можете получить непред- виденные результаты. Если вы собираетесь монтировать два гибких диска, убедитесь, что у вас есть и каталог /mnt, и /mnt1. Строка 23 делает монтируемую файловую систему доступной только для чтения в случае, если была указана опция -r, что выполняется до- бавлением символов -r к имени каталога. Это не является частью имени каталога, но когда shell выполняет обработку команды, пробела между именем каталога и -r достаточно, чтобы распознать -r как опцию. Строка 24 соответствует опции -s и присваивает переменной SYSTEM значение sysv. Это означает, что нужно использовать другие соглашения об именах устройств. Строки 25-34 выполняют проверку на ошибки в командной строке. Лю- бая опция, отличная от уже проверенных, является ошибкой, поэтому все, что соответствует улавливающей ветке оператора case (*), считается не- допустимой опцией. В этом случае выводится синтаксическая подсказка, и программа завершается. В строках 39-42 выполняется вся основная работа. Оператор case действует в соответствии со значением переменной SYSTEM. Если оно рав- но "sysv", выполняется строка 40. В противном случае выполняется стро- ка 41 для системы XENIX. Обратите внимание, что в нашей версии команд- ного файла mntf в строке sysv имеется только переменная с номером уст- ройства. Если вы используете System V, вы можете добавить переменную для указания плотности записи или другие параметры, которые вам нужны. Строка 41 выполняет версию команды, рассчитанную на систему XENIX. Переменная CMD содержит, как мы отмечали, команду монтирования (mount) или размонтирования (umount). Последовательность символов /dev/fd указывает файл устройства для гибкого диска. Переменная DRIVE равна 0 или 1. Переменная DENSITY указывает устройство с высокой или низкой плотностью записи. Если должна быть выполнена команда монтиро- вания, переменная DIR содержит каталог. Если выполняется размонтирова- ние, значение переменной DIR равно нулю. ЗАМЕЧАНИЕ ПО ВОПРОСУ БЕЗОПАСНОСТИ Обычно только суперпользователь (root) может монтировать файловую систему. В больших системах это имеет смысл. Однако на небольших настольных машинах это может быть слишком ограничивающим фактором. Для того чтобы обойти это требование, используйте возможность изменения прав доступа. Чтобы позволить любому пользователю выполнять команды монтирования и размонтирования, примените следующие команды: # chown root /etc/mount <- делает пользователя root владельцем модуля /etc/mount # chmod 4511 /etc/mount и дает возможность выполнять команду mount всем пользователям # chown root /etc/umount <- делает то же самое для команды # chmod 4511 /etc/umount размонтирования Эти команды облегчают всем пользователям работу с гибким диском, но одновременно открывают огромную дыру в защите системы. Если кто-ли- бо уже проложил тропинку прав доступа на гибкий диск (см. главу 9), то монтирование файловой системы продолжит эту тропинку в главную систему и позволит такому пользователю стать суперпользователем всей системы в целом просто с гибкого диска! -------------------------------------------------------------- ИМЯ: 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 fsck df du ------------------------------------------------------------- РАСЧЕТЫ, СВЯЗАННЫЕ С БЛОКАМИ Еще одним важным вопросом, имеющим отношение к физическим уст- ройствам и логическим файловым системам, является определение местона- хождения определенного блока на жестком диске. Номер этого блока вы- числяется по номерам цилиндра, дорожки и сектора. Знание номеров блоков становится важным, когда на диске появля- ется дефектное место. Это дефектное место отмечается номерами цилиндра и головки. Вам необходимо вычислить, какие блоки попадают в дефектную область и занести их номера в таблицу дефектных блоков. Обратная задача также важна. Если программа 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 ПРИМЕР ВЫЗОВА 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, пе- реданные по конвейеру. Они размонтируют все файловые системы. ------------------------------------------------------------ ИМЯ: lrgf ------------------------------------------------------------ lrgf Создает файл максимально возможного размера НАЗНАЧЕНИЕ Выполняет операции записи в файл до тех пор, пока не обнаружится граница размера файла. ФОРМАТ ВЫЗОВА 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