- Главный (стартовый) файл проекта
- Как выделить (пометить, обозначить) главный файл
- Какой тип файла сделать главным
- Идеология построения приложения
- Точка останова. Read Events
- Аварийное прекращение приложения. Настройка ON ShutDown
- Надо ли давать команду QUIT для закрытия приложения
- Как скрыть главное окно FoxPro (SCREEN)
- Как скрыть системные ToolBar
- Настройка среды FoxPro
- Запуск командного процессора
- История команд
- Восход солнца вручную
- Один из интереснейших вопросов в ОС — старт системы. Как именно происходит старт? Как оказалось здесь достаточно много вопросов и трудностей. Более точно остановимся на процессе init и группе rc-файлов. Для экспериментов использован диск Red Hat Linux 6.2.
- Голосовать будем списком
- Замуровали, демоны
- Снова к вопросу об анатомии вампиров
- Если вам понравилась статья, поделитесь ею с друзьями:
- 1 «Сердце» программы MAKE
- Построение файла описаний для утилиты MAKE.
Главный (стартовый) файл проекта
Конечной целью разработки приложения является создание одного (или нескольких) EXE-файла. Но это то, что должно получиться в результате. А на этапе его создания мы имеем большую кучу самых разных файлов (формы, запросы, программные модули, классы и т.п.).
Возникает закономерный вопрос, какой файл из этой кучи в готовом файле EXE должен запускаться первым? А как этот файл выделить (пометить, обозначить)?
Вот этот самый файл, который в готовом файле EXE должен запускаться первым и называется главным (стартовым) файлом
. О нем и пойдет речь в данном разделе.
Как выделить (пометить, обозначить) главный файл
На этапе создания готового EXE-файла все наши файлы включаются в общий файл проекта (файлы с расширением PJX и PJT). Файл проекта — это средство как-то упорядочить ту кучу файлов, из которой впоследствии будет собран готовый EXE-файл, а, кроме того, это инструмент собственно сборки EXE-файла.
Так вот, в FoxPro главный (стартовый) файл может быть обозначен только и исключительно внутри файла-проекта
. Не существует никаких особых ключевых слов или синтаксических конструкций для его выделения в программном коде.
По умолчанию, первый добавленный в проект файл автоматически становиться главным (если это возможно). Такой файл выделяется в проекте жирным шрифтом.
Если Вас не устраивает такой автоматический выбор, то Вы можете в любой момент указать в качестве главного (стартового) файла нужный Вам файл. Для этого щелкните внутри проекта правой клавишей мыши по нужному файлу и в появившемся меню выберите пункт «Set Main». Выбранный файл будет выделен жирным шрифтом, а файл, ранее обозначенный как главный (стартовый) файл, сбросит свое выделение и станет обычным (не главным) файлом.
В пределах одного файла — проекта может быть только один главный (стартовый) файл
В принципе, допустимо вообще не указывать главный (стартовый) файл. Однако из такого проекта невозможно будет создать готового EXE-файла. На этапе компиляции возникнет ошибка с сообщением о том, что Вы не указали главный (стартовый) файл проекта.
Какой тип файла сделать главным
Главным (стартовым) файлом может быть
- Программный файл (PRG)
- Форма (SCX)
- Меню
Ну, по сути, файл меню — это и есть программный файл. Так исторически сложилось. Точнее, разработчики FoxPro пока «не доросли» до коренной переделки идеологии построения меню, как они это сделали с формами, а в 9 версии и с отчетами.
Дело в том, что хотя на этапе проектирования меню — это файлы с расширением MNT, MNX, но после создания макета меню необходимо запустить его генерацию. Результатом генерации меню становятся файлы MPR, MPX. Вот эти-то файлы и есть обычные файлы PRG и FXP, только с измененным расширением.
Следовательно, по сути, выбор стоит между программным файлом и файлом формы.
Так вот, всегда указывайте в качестве главного (стартового) файла программный файл
. Более того, это должен быть именно файл PRG и ничто другое.
Причин этому множество. По мере дальнейшего обсуждения Вы увидите, что очень многое из того, что надо сделать в главном (стартовом) файле очень трудно, а иногда и просто невозможно реализовать в форме.
В принципе, в зависимости от конкретной задачи, часть операций в главном (стартовом) файле, которые будут описаны далее, можно и не выполнять. А оставшиеся операции можно «втиснуть» в форму. Но я не советовал бы этого делать. Программы имеют «привычку» разрастаться. А использование в качестве главного (стартового) файла формы сильно сужает возможность модификации.
Идеология построения приложения
Содержимое главного (стартового) файла проекта зависит в первую очередь от конкретной задачи. Например, если целью Вашего проекта является создание COM-сервера, то в главном (стартовом) файле вообще ничего не будет.
В FoxPro существуют следующие идеологии построения приложений:
- На базе основного окна FoxPro (SCREEN)
- На базе «As Top-Level» форм
Построение приложения на базе основного окна FoxPro (SCREEN) предполагает, что в конечном приложении пользователь будет видеть это основное окно (разумеется, со своим меню и ToolBar) и все формы будут открываться внутри этого основного окна.
Построение приложения на базе «As Top-Level» форм предполагает, что основное окно FoxPro (SCREEN) вообще не будет отображаться в конечном приложении. А в качестве основного окна будет выступать созданное программистом окно со свойством ShowWindow = 2 — «As Top-Level form»
Честно говоря, я не вижу особого смысла в построении приложений на базе «As Top-Level» форм. Ведь даже в таком приложении, так или иначе, необходимо будет создать главную форму. А зачем, когда эта форма и так уже есть (основное окно FoxPro)?
Как элемент интерфейса (например, для ввода пароля при входе в программу) «As Top-Level» формы вполне на своем месте. Но строить все приложение целиком на их основе мне представляется неразумным. Да и программно это несколько сложнее. Впрочем, это тема для отдельного обсуждения.
Дальнейшее описание содержимого главного (стартового) файла будет стротиться исходя из предположения, что создается приложение на базе основного окна FoxPro (SCREEN). Впрочем, даже если Вы строите приложение на базе «As Top-Level» форм содержимое главного (стартового) файла останется практически таким же. Отличия будут в некоторых деталях. По мере описания я буду указывать на эти детали.
Точка останова. Read Events
При создании приложения основным управляющим элементом всего приложения является главное меню. Это значит, что в главной (стартовой) программе необходимо сделать вызов этого меню
Синтаксически все абсолютно правильно. Более того, когда Вы будете запускать главный (стартовый) файл на этапе разработки приложения все будет работать нормально. Но вот после того, как Вы создадите готовый EXE-файл и запустите его, то вместо ожидаемого приложения Вы увидите «странный» эффект.
Окно FoxPro мелькнет на экране и тут же закроется.
Причиной такого «странного» поведения является то, что Вы «забыли» указать FoxPro, в каком месте ему надо остановиться и подождать реакции пользователя. На этапе отладки такой «точкой останова» является ранее открытая среда FoxPro. Но в готовом файле EXE до него никакой среды FoxPro открыто не было! Чтобы создать «точку останова» надо дать специальную команду
Т.е. содержимое главного (стартового) файла будет выглядеть так:
DO MainMenu.mpr
READ EVENTS
Вот теперь, в готовом файле EXE, когда программа дойдет до команды READ EVENTS, то произойдет остановка в ожидании реакции пользователя.
Имейте в виду, что одновременно, во всем приложении может быть активна только одна команда READ EVENTS. Вызов другой команды READ EVENTS не приведет к ошибке, но эта команда будет просто проигнорирована. Чтобы отменить действие команды READ EVENTS надо дать специальную команду
По этой команде будет отменено действие команды READ EVENTS и выполнение перейдет на команду, следующую за командой READ EVENTS. Т.е., если Вы дали команду CLEAR EVENTS в какой-либо процедуре, то все то, что стоит следом за этой командой вообще никогда не будет выполнено.
Так, где же давать команду CLEAR EVENTS? Разумеется, в специальном пункте меню «Выход».
Если Вы создаете приложение на базе «As Top-Level» форм, то команду CLEAR EVENTS надо давать в событии UNLOAD Вашей главной формы.
Итого, получается примерно такая логика:
- Запускается главный (стартовый) файл
- Активизируется основное меню
- По команде READ EVENTS организуется «точка останова» для ожидания действий пользователя
- Команда CLEAR EVENTS прекращает действие команды READ EVNETS, завершает выполнение главного (стартового) файла, что приводит к закрытию приложения FoxPro.
Аварийное прекращение приложения. Настройка ON ShutDown
До сих пор, речь шла о «штатном» завершении. Т.е. когда пользователь дисциплинированно использует все положенные пункты меню для выхода из приложения. Но ведь пользователь может закрыть приложение, нажав на крестик в правом верхнем углу основного окна FoxPro или, например, через окно «Диспетчер задач Windows» (Ctrl+Shift+Esc).
Если все оставить так, как было описано до сих пор, то после такой попытки пользователя выскочит сообщение об ошибке
Cann’t quit Visual FoxPro
Причина такого сообщения в том, что осталась активной команда READ EVENTS. Именно она и вызывает такое сообщение об ошибке в описанной ситуации. Чтобы перехватить описанные события закрытия приложения используется специальная настройка
В принципе, можно просто написать
ON SHUTDOWN CLEAR EVENTS
Но, обычно перед закрытием приложения надо выполнить ряд предварительных операций. Каких? Это уже зависит от Вашего приложения. Ну, например, можно спросить пользователя о том, действительно ли он хочет выйти из приложения или это у него «рука дрогнула». В общем случае одной команды недостаточно. Нужен вызов процедуры. Например:
ON SHUTDOWN DO MyExitProcedure
И вот уже в этой процедуре MyExitProcedure и надо дать команду CLEAR EVENTS. Причем эта команда должна быть самой последней, поскольку в момент ее выполнения управление будет передано на команду, следующую за командой READ EVENTS и все то, что написано после CLEAR EVENTS просто не будет выполнено.
Для универсальности, желательно в пункте меню «Выход», вместо простой команды CLEAR EVENTS также сделать вызов этой процедуры. Тогда у Вас будет один общий код, обрабатывающий выход из Вашего приложения при любых ситуациях.
В принципе, собственно процедуру MyExitProcedure можно расположить в главном (стартовом) файле. Поскольку главный (стартовый) файл — это «корневой» файл, из которого осуществляется вызов любых других файлов, то расположенная таким образом процедура будет «видна» и доступна из любого места Вашего приложения.
Однако я все-таки советовал бы вынести эту процедуру в отдельный одноименный файл PRG или в метод некоего глобального объекта. Причина этой рекомендации в том, что отдельный файл или метод класса проще модифицировать.
Если Вы делаете приложение на базе «As Top-Level» форм, то вызов этой процедуры надо организовать еще и в событии QueryUnload главной формы. Точнее так, в событии QueryUnload главной формы надо перенаправить вызов на собственно метод, организующий закрытие всего приложения.
В результате, содержимое главного (стартового) файла приобретает следующий вид
ON SHUTDOWN DO MyExitProcedure
DO MainMenu.mpr
READ EVENTS
Надо ли давать команду QUIT для закрытия приложения
В FoxPro существует команда QUIT, которая приводит к немедленному закрытию приложения FoxPro. Правда эта команда также перехватывается настройкой ON SHUTDOWN и также по ней невозможно выйти из приложения, если активна команда READ EVENTS.
Возникает резонный вопрос, а нужна ли эта команда, если приложение FoxPro и так само закроется, когда завершится выполнение главного (стартового) файла?
Ну, лично я считаю, что это команда для ленивых программистов. Т.е. для тех, кому лень отслеживать все открытые в приложении объекты. Как я уже упоминал ранее, закрытие приложения в общем случае — это очень не тривиальная задача.
Ну, например, пользователь редактировал какие-либо данные в форме и нажал на крестик или пункт меню «Выход». Следует ли организовать «штатное» закрытие формы или просто «прихлопнуть» все открытые процессы?
По «правильному» логично спросить пользователя желает ли он сохранить внесенные изменения. Т.е. организовать «штатное» закрытие всех открытых объектов. А команда QUIT просто «прихлопнет» все открытые объекты без каких-либо дополнительных вопросов и все!
Есть и более тонкие моменты. Т.е. по хорошему, в процедуре MyExitProcedure надо организовать «штатное» закрытие всех открытых объектов и после команды READ EVENTS (где собственно и предполагается давать команду QUIT) вообще не должно остаться ничего такого, что следовало бы закрывать именно командой QUIT. Если все-таки что-то осталось, то это явная недоработка разработчика. И эта недоработка может очень сильно «аукнуться» в готовом приложении. Без команды QUIT Вы отловите эту проблему еще на стадии отладки приложения.
Кроме того, использование команды QUIT может осложнить отладку. Что, каждый раз после запуска главного (стартового) файла заново открывать среду FoxPro? Впрочем, как это обойти, чуть ниже.
Итого, я не рекомендовал бы использовать команду QUIT.
Как скрыть главное окно FoxPro (SCREEN)
В большинстве случаев, вне зависимости от того в какой идеологии Вы разрабатываете свое приложение при загрузке среды FoxPro желательно скрыть главное окно FoxPro (SCREEN). Если Вы разрабатываете приложение в основном окне FoxPro, то потом его можно будет отобразить. Ну, а если приложение на базе «As Top-Level» форм, то отображение его и не нужно.
Можно первой же командой в главном (стартовом) файле дать команду
_SCREEN. Visible = . F.
Окно FoxPro действительно скроется. Однако перед этим успеет все-таки «мелькнуть». Не хорошо.
Чтобы подавить открытие главного окна следует использовать файл конфигурации Config.fpw. Это обычный текстовый файл. В нем должна быть строчка:
SCREEN=OFF
Более подробно о файле конфигурации рассказано в других разделах. Данная статья посвящена только главному (стартовому) файлу.
Чтобы снова отобразить главное окно FoxPro (SCREEN) следует дать команду
_SCREEN. Visible = . T.
Если главное окно FoxPro (SCREEN) и до этой команды было отображено, то от этой команды хуже не будет.
В результате, содержимое главного (стартового) файла приобретает следующий вид
ON SHUTDOWN DO MyExitProcedure DO MainMenu.mpr _SCREEN. Visible = . T. READ EVENTS
Как скрыть системные ToolBar
Когда Вы запускаете свое приложение в режиме отладки, то системное меню заменяется Вашим меню. Но вот системный ToolBar остается «висеть», как ни в чем не бывало.
Разумеется, Вы не потащите пользователю этот ресурсный файл. Как следствие, на машине клиента системные ToolBar вообще не появяться. Просто потому, что там не будет ресурсного файла с машины разработчика.
Однако если на этапе отладки Вам все-таки необходимо скрыть системные ToolBar, то это можно сделать набором команд
Имя того или иного ToolBar можно посмотреть в заголовке самого ToolBar (если он не «приклеен» к меню) или через пункт меню View, подпункт ToolBars
Например, скрыть стандартную панель можно командой
HIDE WINDOW «Standard»
Снова активизировать стандартную панель можно командой
SHOW WINDOW «Standard»
Проверить тот факт, что та или иная панель в настоящий момент активна можно используя команду WEXIST()
IF WEXIST(«Standard») = . T.
HIDE WINDOW «Standard»
ENDIF
Таким образом, если Вам очень хочется скрыть системные ToolBar в режиме отладки, то несложно написать простые процедуры их закрытия в начале главного (стартового) файла и восстановления после команды CLEAR EVENTS.
Но, повторюсь, особого смысла в готовом приложении это не имеет. Поскольку там их и так не будет.
Настройка среды FoxPro
Ранее я вскользь уже упомянул тот факт, что просто запустить среду FoxPro недостаточно. Надо сделать некоторые предварительные настройки. Хотя бы настройку ON SHUTDOWN.
Дело в том, что среда FoxPro по умолчанию настроена таким образом, чтобы облегчить создание новых и модификацию старых приложений. Т.е. она настроена для удобства разработчика
. Но в готовом приложении такая настройка среды FoxPro не просто некорректна. Она может оказаться недопустимой!
Часть настроек среды FoxPro можно увидеть через пункт меню Tools, подпункт Options. А чтобы получить эти настройки в виде кодов нажмите и удерживайте клавишу «Shift» и левой кнопкой мыши нажмите на кнопку «Ok». В командное окно будет выведены все текущие настройки формы Options. Вы можете их просто скопировать и вставить в главный (стартовый) файл. Разумеется, предварительно просмотрев, что именно из них действительно нужно для успешной работы Вашего приложения.
Сложность в том, что на этапе отладки приложения все-таки нужны несколько другие настройки, чем в готовом приложении.
Например, на этапе отладки хорошо бы иметь возможность прервать выполнение какого-либо процесса по нажатию клавиши «Esc», но в готовом приложении этого допускать ни в коем случае нельзя. Это регулирует настройка SET ESCAPE.
Т.е. получается, что необходимо как-то отличать, в каком режиме было запущено приложение. В режиме отладки или как готовый файл EXE.
Есть несколько вариантов определения режимов работы. Самый простой — это посмотреть значение свойства
Если это свойство имеет значение 0, то мы находимся в режиме отладки. Т.е. получается что-то вроде:
* Общие настройки вне зависимости от режима работы IF _VFP. StartMode = 0 * Настройки только для режима отладки ELSE * Настройки только для готового приложения ENDIF
Есть и еще одна проблема настроек. Дело в том, что при открытии Private DataSession часть настроек, связанных с работой с данными сбрасываются в значения по умолчанию. Полный список таких настроек Вы можете посмотреть в описании к команде «SET DataSession». Причем для некоторых настроек эти самые значения по умолчанию отличаются в зависимости от того, в какой DataSession мы находимся.
Т.е. получается, что недостаточно просто один раз сделать настройки в главном (стартовом) файле. Нужно еще повторить часть настроек в каждой Private DataSession.
Следовательно, выполнение настроек среды FoxPro надо вынести либо в отдельную процедуру, либо оформить как метод класса. Если как метод класса, то либо как метод некоей базовой формы, на основе которой будут созданы все формы Вашего проекта, либо как метод класса Custom, экземпляр которого будет «бросаться» на нужные формы.
Наконец, еще одна проблема настроек. По завершении работы приложения надо вернуть настройки в то состояние, в котором они были на момент запуска приложения.
На первый взгляд, это кажется абсолютно бессмысленным требованием. Но не надо забывать, что мы отлаживаем наше приложение. Это значит, что есть часть настроек, которые просто обязаны отличаться в зависимости от того, просто мы отлаживаем какую-то форму (процедуру) или запустили приложение в режиме отладки, начиная с главного (стартового) файла.
Например, при отладке триггеров хорошо бы видеть записи помеченные как удаленные. Но в готовом приложении, даже при запуске в режиме отладки, нам видеть эти записи не надо. Это регулирует настройка SET DELETED
Да и в любом случае желательно всегда следовать принципу: намусорил, убери за собой. Для программирования это особенно важно во всех смыслах.
Таким образом, в общем случае, работа с настройками выглядит примерно так:
- Проверяем текущее состояние настройки
- Если текущее состояние настройки отличается от нужного нам значения в данном режиме работы в данном месте, то сохраняем старое значение настройки и устанавливаем новое
- По окончании работы восстанавливаем измененные настройки
Из этой логики следует, что использовать процедуры в принципе можно, но очень уж неудобно. Нужны две отдельные процедуры для установки и для восстановления настроек. А, кроме того, нужно где-то хранить старые настройки.
Более удобным кажется использование классов. Создаются два метода одного и того же класса (возможно больше, ведь для Private DataSession надо установить только часть настроек). А для хранения старых значений настроек можно использовать свойства (Properties) класса.
Тогда остается уточнить, использовать ли класс Custom или класс на базе Form?
По большому счету — это абсолютно одинаковые варианты. Следует только помнить, что методы класса Custom можно запустить не ранее события Init этого класса. Но в любом случае методы собственно формы или любых ее объектов еще не существуют на момент выполнения события BeforOpenTables в DataEnvironment формы. Т.е. автоматическое открытие таблиц, включенных в DataEnvironment формы, произойдет с использованием настроек по умолчанию.
Но в большинстве случаев, это не столь уж и принципиально. Дело в том, что критичными (принципиально важными) в момент открытия таблиц являются следующие настройки:
SET DELETED SET EXCLUSIVE SET MULTILOCKS
Все остальные настройки вполне можно сделать уже после открытия таблиц. Они влияют уже собственно на работу с открытыми таблицами, а не на их открытие.
Настройка SET DELETED принципиально важна, если в DataEnvironment включено Local View, поскольку просто нет другого способа отсечь записи, помеченные как удаленные, чтобы они не попали в Local View. Но обычно Local View включают в DataEnvironment с опцией NoDataOnLoad=. T. и наполняют данными в Init-формы. Т.е. когда настройка SET DELETED уже сделана в наших методах
Настройка SET EXCLUSIVE имеет разное значение по умолчанию для Default и Private DataSession. В Private DataSession она имеет значение OFF, что собственно и надо. А в Default DataSession используется ранее сделанная в той же DataSession настройка. Если же для отдельных таблиц принципиально важно открыть их в режиме Exclusive, то используйте одноименное свойство курсора в DataEnvironment — формы.
Настройка SET MULTILOCKS нужна, если делается настройка режима буферизации непосредственно в свойствах курсора в DataEnvironment — формы. Но в этом случае FoxPro сам делает нужную настройку. Т.е. опять же нет необходимости в ручной предварительной настройке.
Возвращаясь к содержимому нашего главного (стартового) файла получаем, что его содержимое уже выглядит примерно так:
* Подключаю библиотеку классов, содержащую ряд полезных классов общего назначения LOCAL loSetting, llIsClass IF "MyClass. VCX" $ SET("ClassLib") llIsClass = . T. ELSE llIsClass = . F. SET CLASSLIB TO MyClass ADDITIVE ENDIF * Класс, устанавливающий глобальные настройки среды (находится в MyClass. VCX) loSetting = CREATEOBJECT("Setting") ON SHUTDOWN DO MyExitProcedure PUSH MENU _MSYSMENU DO MainMenu.mpr _SCREEN. Visible = . T. READ EVENTS ********* Восстановление исходных настроек ON SHUTDOWN POP MENU _MSYSMENU IF m.llIsClass=. F. RELEASE CLASSLIB MyClass ENDIF
Здесь я предполагаю, что в библиотеке классов MyClass. VCX есть класс «Setting» в событии Init, которого происходит установка нужных настроек, а в событии Destroy восстановление исходных настроек. Т.е. удаление переменной m.loSetting означает автоматическое восстановление исходных настроек.
Еще использованы дополнительные команды PUSH MENU и POP MENU, которые сохраняют и восстанавливают системное меню FoxPro.
Обратите внимание на то, что переменные объявляются как LOCAL. Дело в том, что если не объявить переменные, то по умолчанию они получат область видимости PRIVATE. А для переменных главного (стартового) файла это равнозначно объявлению их как PUBLIC, поскольку они будут видны во всех вызванных формах и процедурах.
Как видите, главный (стартовый) файл начинает разрастаться. С этим надо что-то делать. Чем больше листинг программы (код одного метода или процедуры), тем сложнее такой код отлаживать и модифицировать.
Запуск командного процессора
запускается либо при входе пользователя в
систему, и в дальнейшем
отдает команды в его
, либо из какой-нибудь программы (
команде пользователя).
Частным случаем является
из другого
. Например, вы работаете в и хотите получить
более удобные средства
; для этого
вызывается . Тогда вы просто набираете команду
и оказываетесь в среде
, запущенного
этой команде. При этом обычно меняется вид приглашения
.
Каждый
при запуске пытается выполнить свои
стартовые файлы, вначале системные (общие для всех пользователей), а
затем пользовательские. Общие файлы лежат в , индивидуальные — в
домашнем каталоге пользователя. Если
запускается
при входе пользователя в систему (в таком случе он называется
—
, запущенный при входе в систему), то
после стартовых файлов он выполняет еще и
-файлы в том же
порядке: сначала общий
—
из , затем — индивидуальный, из
домашнего каталога.
-файлы — это тоже стартовые файлы
, все стартовые файлы фактически представляют собой скрипты
на языке
и служат для инициализации
для конкретного пользователя.
Настройка
для пользователя позволяет, например,
задать короткие псевдонимы для длинных часто используемых команд и
т.п.
Некоторые
при входе в систему выполняют сначала
-файлы, а затем — стартовые файлы, это зависит от того, как они
были скомпилированы.
Другие
принимаются за выполнение каких-либо
стартовых файлов только при входе пользователя в систему. У
обычно есть
, который можно дать, чтобы
сымитировать вход в систему и заставить его выполнить
-файлы.
, в отличие от других, использует более
сложный
выполнения стартовых и
-файлов. Если он запущен
как
, то он выполняет , если такой
есть.
Затем делается попытка выполнить . Если такого файла
нет, пытается выполнить
, а если нет и такого
файла, то выполняется . Если запущен не как
, то при старте он выполняет только
. Если же
был запущен как (т.е. является символьной ссылкой на ), то
при старте он ведет себя так же, как и .
История команд
Все
запоминают введенные пользователем команды
(их
называется
). Во время сеанса работы
хранит
в памяти, а
окончании
работы записывает их в
на
.
истории команд хранится в
домашнем каталоге пользователя. В , , он называется , в — , в — , а в
бесплатной версии Korn
(
Korn
— pdksh) его
умолчанию нет вообще.
Многие
позволяют повторить вызов ранее введенной
команды
ее номеру или начальным буквам. О том, как это делать,
подробнее сказано ниже в разделе «Повторение и модификация ранее
введенных команд».
Имейте в виду, что
умолчанию
истории команд может быть
доступен для чтения не только тому, кто вводил команды, но и другим
пользователям. Чтобы не сделать систему уязвимой, следует избегать
ввода каких бы то ни было паролей в
. Например,
возможно вызвать
или программу доступа к серверу баз
данных , указывая
в
:
lynx ftp://user:password@URL mysql -u root -p password
Так как эти команды сохранятся в файле истории вместе с другими,
кто-то потом сможет прочесть их и узнать какие-то из ваших паролей.
истории команд ограничен
размеру.
умолчанию, хранит
500 команд, — 1000, — 100, — в зависимости от версии.
Часто не создает
вовсе, и дает
только к
командам, которые были введены в течение текущего сеанса работы с
ним. Можно изменить число хранимых команд, указав иное
переменной, в которой оно хранится.
На главную
-> MyLDP
->
Тематический каталог
->
Процесс начальной загрузки системы
Восход солнца вручную
Один из интереснейших вопросов в ОС — старт системы. Как именно происходит старт? Как оказалось здесь достаточно много вопросов и трудностей. Более точно остановимся на процессе init и группе rc-файлов. Для экспериментов использован диск Red Hat Linux 6.2.
Основной управляющий файл для процесса init — это /etc/inittab. Приведем его с незначительными исключениями и модификациями:
# inittab Файл описывает, как перейти # к конкретному уровню # Author: Miquel van Smoorenburg, # <miquels@drinkel.nl.mugnet.org> # Modified for RHS Linux by Marc Ewing # and Donnie Barnes # Уровни выполнения для RHS: # 0 - останов (не устанавливайте # initdefault в это значение) # 1 - Single user mode - однопользова- # тельский режим # 2 - Multiuser, многопользовательский без # NFS (Аналог 3, если не используете сеть) # 3 - Полностью многопользовательский # режим # 4 - не используется (точнее, не имеет # смысла по умолчанию) # 5 - X11 - графический режим со # стартом оболочки # 6 - reboot - перезагрузка (не устанавли- # вайте initdefault в это значение) id:3:initdefault: # Инициализация системы si::sysinit:/etc/rc.d/rc.sysinit l0:0:wait:/etc/rc.d/rc 0 : l6:6:wait:/etc/rc.d/rc 6 # Что выполняется на каждом уровне ud::once:/sbin/update # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now # ИБП подключен и работает корректно pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down> # Выполнение gettys на стандартных # уровнях 1:2345:respawn:/sbin/mingetty tty1 : 6:2345:respawn:/sbin/mingetty tty6 # Выполнение xdm на уровне 5, # xdm - отдельная служба x:5:respawn:/etc/X11/prefdm -nodaemon
Формат этого файла практически не отличается от других вариантов Unix. Каждый элемент занимает 4 поля: имя, уровни старта, вариант обработки (ждать окончания — wait, рестартовать после окончания — respawn, установить стандартный уровень для старта — initdefault и т.д.), непосредственно выполняемая на данном уровне команда. Из отличий от других вариантов Unix стоит отметить наличие опции ctrlaltdel.
Что произойдет, если в приведенном файле поменять initdefault значение с 3 на 5? Это будет переход от алфавитно-цифрового входа к графическому входу в систему и наоборот. Именно это значение меняет linuxconf при выборе соответствующей опции.
В тексте явно видно деление по уровням. Фактически они отличаются набором доступных подсистем или служб, возможностью работать в многопользовательском режиме и т.п. В любой момент времени проверить текущий уровень можно командой /sbin/runlevel.
Менее известен другой файл, /etc/initscript. Разработчики отводили ему роль, аналогичную /etc/security/limits.conf, который позволяет задать лимиты для всех, группы или конкретного пользователя. /etc/initscript же выполняется перед стартом каждого из процессов в /etc/inittab. При этом собственно выполняемая команда передается как четвертый параметр. В этом файле можно задать там любые специфические действия, в частности, установку тех же самых лимитов, umask или еще что-нибудь, но уже не для пользователя, а для каждой команды из /etc/inittab файла. Обратите внимание на пример (см. man initscript), дабы не попасть в дурную ситуацию. Другой пример:
ulimit -c 0 ## core-dump прощай eval exec "$4"
Голосовать будем списком
Остановимся на работе rc-файлов. Скажем, для перехода на третий уровень при старте надо выполнить последовательно /etc/rc.d/rc.sysinit, <etc/rc.d/rc 3>, /sbin/update, а затем запустить /sbin/mingetty на всех эмуляторах консоли. Каковы их функции? Файл rc.sysinit выполняет ряд начальных действий, независимых от уровня. Вот точный порядок этих действий (естественно, часть из них выполняется опционно):
Запуск fsck может быть принудительно отключен с целью уменьшения времени рестарта при наличии файла /fastboot, а также включен при наличии /forcefsck; можно <заказать> дополнительные опции (/fsckoptions). Появление этих файлов может быть результатом выполнения shutdown с соответствующими ключами: -f (пропуск fsck при старте); -F (принудительный fsck при старте).
Обратили ли вы внимание на то, что <включение подкачки> присутствует два раза? В действительности, дважды делается попытка выполнить одну и ту же команду: swapon -a. Зачем? Из комментариев можно вычитать, что первая команда присоединяет к области подкачки разделы, а вторая — файлы. Так как команда одна и та же, мы, конечно, не поверим комментариям и попробуем проверить их опытным путем.
Первым делом создаем файл подкачки на отдельно смонтированной системе:
root@localhost /root]# dd if=/dev/ zero bs=1k count=2048 of=/r6/myswap 2048+0 блоков прочитано 2048+0 блоков записано [root@localhost /root]# mkswap /r6/myswap 2048 Setting up swapspace version 0, size = 2093056 bytes [root@localhost /root]# Добавляем строчку в /etc/fstab: /r6/myswap swap swap defaults 0 0
Проверяем результат после перезагрузки, запрашиваем текущее использование устройств подкачки:
[root@localhost /root]# swapon -s Filename Type Size Used Priority /dev/hda5 partition 104380 0 -1 /r6/myswap file 2044 0 -2 [root@localhost /root]#
Если посмотреть информацию о перезагрузке, обнаружится, что, конечно, swapon попытается подключить /r6/myswap два раза. Первый раз (/r6 еще не смонтирована) будет сообщение об ошибке (и даже FAILED), хотя подключение раздела происходит. Второй раз все проходит нормально (благо еще и диагностика в /dev/null). Обратите внимание на то, что файл для подкачки должен существовать (как-то мне попалась команда mkswap, которая его заполняла, но не создавала) и при этом не содержать <дыр> (с чего бы это?).
Sysctl позволяет зафиксировать ряд параметров и обеспечить (через /etc/sysctl.conf) их установку после перезагрузки. Вот как выглядел /etc/sysctl.conf сразу после инсталяции:
# Disables packet forwarding net.ipv4.ip_forward = 0 # Enables source route verification net.ipv4.conf.all.rp_filter = 1 # Disables automatic defragmentation net.ipv4.ip_always_defrag = 0 # Disables the magic-sysrq key kernel.sysrq = 0
Замуровали, демоны
rc — именно этот командный файл и отвечает, в основном, за переход между уровнями.
Разрешение на выполнение нужного набора скриптов можно задавать интерактивно. Для этого достаточно обратить внимание на заголовочек, указывающий на то, что нажатие I можно использовать для управления процессом старта. Реально после нажатия появляется файл /var/run/confirm, который и служит флагом интерактивного режима загрузки. Для перхода на уровень выполняются все файлы в соответствующем подкаталоге rc$runlevel.d. Имена этих файлов, как правило, начинаются с большой (это существенно) буквы S или K. Если первая буква иная, то файл просто не участвует в процессе межуровневого перехода. Файлы на S отвечают за старт службы, а файлы на K — за остановку какой-либо службы. Обратите внимание, что при переходе на уровень 3 прямо со старта, мы никак не используем файлы из rc2.d — только rc3.d. Этот <кумулятивный> вариант отличается от того, который принят, например, в Unix System V. Там при старте, последовательно выполняются стартовые файлы всех промежуточных каталогов, в частности, rc1.d, rc2.d и т.п.
После начальной буквы идут две цифры (маловато будет, достаточно типично сейчас использование трех). Эти цифры позволяют отсортировать командные файлы и указать точный порядок запуска. Ясно, что это достаточно важно. Например, сетевые сервисы должны стартовать после того, как заработают сетевые интерфейсы. После цифр идет имя службы — подсистемы.
Для управления набором доступных служб можно использовать программу конфигурирования linuxconf. Что означает разрешить или запретить использование какой-либо службы с точки зрения всяких там файлов? Запрещение старта какого-либо сервиса просто приводит к удалению соответствующей ссылки из каталогов rcn.d, а разрешение — к появлению. А как же обеспечивается корректная установка номера у соответствующей ссылки? Мы же должны обеспечить правильный порядок выполнения старта для подсистем. Неужели linuxconf обязан знать про роль всех служб и что-то интеллектуально вычислять?
Все устроено гораздо проще. Обратите внимание на часть заголовка файла /etc/rc.d/init.d/atd:
# Запуск демона # chkconfig: 345 40 60 # processname: atd
Заглянем в сам файл /etc/rc.d/init.d/atd. Мы сразу видим, что реально возможных опций больше, чем стандартные start и stop. Имеются еще restart, reload и status. Такая ситуация тоже достаточно типична. Старт, останов и проверка состояния демона выполняется рядом функций типа daemon, killproc, status. Если все происходит по плану, то создается (удаляется) файл /var/lock/subsys/atd.
Рассмотрим теперь подробнее вышеуказанные процедуры daemon, killproc, status. Они определяются (вместе с рядом других) в /etc/rc.d/init.d/functions (а тот пользуется определениями из /etc/sysconfig/init). Уже по названию ясно для чего они предназначены — старт, останов и проверка статуса демона.
Перед стартом демона всегда делается проверка наличия его в системе. Поскольку демон может вызываться из скрипта, то для проверки текущего состояния можно заказать точное имя (-check name). Так как появление dump-а демона может приводить к проблемам с security, то все демоны запускаются в режиме без core-dump. Сам старт выполняется командой initlog $INITLOG_ARGS -c <$*>, которая и стартует демона и записывает информацию об этом в лог.
Останов демона выполняется процедурой killproc. Данная функция предполагает один аргумент в виде имени демона и, возможно, еще один для указания сигнала, который и будет послан демону для окончания. S IGKILL очень часто может быть не желателен, так как могут возникнуть разнообразные проблемы типа блокирования ресурсов. Поэтому, если сигнал назначен, то используется только он, если не назначен, то сначала SIGTERM и, если данный сигнал не позволит упокоить демон за разумное время, то посылается SIGKILL. Последним действием удаляется флаговый файл /var/run/подсистема.pid.
Наконец status позволяет проверить текущее состояние работы подсистемы. Если процесс работает, то просто сообщается данный факт. Если не работает, то делается проверка на наличие флаговых файлов (/var/run/подсистема.pid и /var/lock/subsys/подсистема), которые должны блокировать повторный запуск. Естественно наличие их диагностируется как ошибка.
Кроме этого, в файле functions есть объявления action — просто выполнить действие (без каких-либо проверок) и зафиксировать его в логе; confirm — генерируемый запрос на подтверждение продолжения работы; другие макросы. Action необходимы в тех случаях, когда работа службы обеспечивается непосредственно ядром системы, т.е. демон для работы не нужен. Соответственно к этой группе можно отнести конфигурирование сетевой подсистемы (например, ifconfig не должен работать непрерывно), монтирование nfs-систем и т.п.
daemon -check sleep /etc/ rc.d/init.d/mysleep
был бы вполне корректным (демон есть, но сидит в тине). В принципе старт демонов в различных вариантах Unix организуется разными способами.
Снова к вопросу об анатомии вампиров
Заметим, что для простой проверки можно использовать базу rpm. Например, у нас возникло подозрение, что подменили login (как мы помним, а если не помним, то используем which, — /bin/login):
[root@localhost rpm]# rpm -q -f /bin/login util-linux-2.10f-7 [root@localhost rpm]# rpm -V util-linux-2.10f-7 S.5. T c /etc/pam.d/login [root@localhost rpm]#
Первая из команд позволяет определить пакет, из которого пришел /bin/login, вторая требует проверки всех файлов пакета. В данном случае обнаружена только модификация конфигурационного файла /etc/pam.d/login (S — размер, 5 — контрольная сумма MD5, T — время модификации). Аналогично, конечно, можно попробовать сказать:
[root@localhost rpm]# rpm -V -a S.5. T c /etc/services S.5. T c /etc/localtime . T c /etc/nsswitch.conf
При использовании одного из стандартных средств (иногда они поставляются непосредственно с системой и общеизвестны) бывают попытки подмены данных после подмены программы. Поэтому новые средства предполагают шифрование базы данных файлов. В принципе, конечно, лучше хранить эти данные отдельно.
Можно использовать и какое-либо средство собственной разработки. В мою копилку недавно прислали соответствующий экземпляр скрипта специально для проверки контрольной суммы на компьютере-источнике и после копирования на новом компьютере. Скрипт прислан, будто специально, для рубрики <найдите 10 ошибок> и, похоже, составлялся под лозунгом <как не надо писать на bash>:
#!/bin/sh # lspr subDirSrc Usage () { echo <\nUsage: cks_cd directory\n> exit 1 } if [ $# = 0 ] ; then Usage ; fi ########################### #tdir=/cdrom tdir=$1 prot=check_summa if [ ! -d ${tdir} ] ; then echo Directory ${tdir} does not exist Usage fi if [ -f $prot ] then rm $prot fi for file in `find ${tdir} -name <*>` do if [ -f ${file} ] then cksum ${file} | sed -e < s/[^0-9]. *//g> >> $prot fi done cksum $prot | sed -e < s/[^0-9].*//g> ##rm $prot
Автор письма предлагает особо рассмотреть вариант копирования файлов через Windows-компьютер (чем почти гарантируется несовпадение общей контрольной суммы), хотя и без этого скрипт великолепен.
Журнал «Открытые системы», #02, 2001 год // Издательство «Открытые системы»
( www.osp.ru
)
Постоянный адрес статьи:
Если вам понравилась статья, поделитесь ею с друзьями:
- 11.1 «Сердце» программы MAKE: Файлы описаний.
- 11.2. Запуск программа MAKE.
- 11.3. Использование макроопределений для утилиты MAKE.
- 11.4. Определение правил вывода.
- 11.5. Использование файлов . MAK.
Утилита разработки программ MAKE поможет вам в разработке программ, содержащих более одного модуля. Утилита MAKE автоматически обновляет файл, устаревший по дате по сравнению с другими родственнами файлами, и бывает полезна в следующих ситуациях:
-При разработке программ утилита MAKE может автоматически обновлять выполняемый файл, как только изменится любой исходный или объектный файл.
-При управлении библиотеками утилита MAKE может автоматически перестроить библиотеку, как только изменится один из модулей библиотеки. — В сетевой среде утилита MAKE может автоматически обновлять локальную копию программы или файла, хранимых в сети, как только основная копия будет изменена.
При запуске утилиты MAKE вы должны задать имя файла. Данный файл, известный под названием «файл описаний утилиты MAKE», содержит инструкции, сообщающие утилите MAKE, какие файлы следует обновить, какие файлы должны измениться перед обновлением, какой тип обновления следует выполнить.
Файл описаний может содержать следующие данные:
TEST. EXE: TEST. C TEST2. C QCL TEST. C TEST2. C
В данном примере TEST. EXE-это файл, который должен быть обновлен, если какой-либо из исходных файлов TEST. C или TEST2. C претерпит изменения. Реальное обновление выполняется с помощью команды QCL на следующей строке. Подробности о файлах описаний вы найдете в Разделе 11.1.
Если вы компилируете ваши программы в среде Quick-C, файл описаний для ваших программ строится автоматически.
В Разделе 11.2 описывается информация, которую следует задать в командной строке утилиты MAKE вместе с именем файла описаний, включая опции программы MAKE. В Разделах 11.3-11.4 описываются другие осбоенности утилиты MAKE.
1 «Сердце» программы MAKE
Утилита MAKE использует «файлы описаний» для того, чтобы определить, какие файлы следует обновлять, когда их обновлять и какие следует для этого выполнить операции. Файл описаний утилиты MAKE состоит из одного или более «блоков описаний», каждый из которых задает описание для одного файла.
В Разделе 11.1.1 рассказывается, как создать простой файл описаний, состоящий из единственного блока описаний.
В Разделах 11.1.1-11.1.2 разъясняется формат блока описаний, правила для их установки и знаки для обозначения отдельных блоков в файле описаний.
В Разделе 11.1.2 рассматриваются файлы описаний программы MAKE, которые строит Quick-C при разработке программ в среде Quick-C.
Построение файла описаний для утилиты MAKE.
В этом разделе для иллюстрации работы утилиты MAKE показано, как построить простейший файл описаний для программы MAKE. Поскольку файл описаний утилиты MAKE-это текстовый файл, для его создания можно воспользоваться любым редактором текстов.
В нашем примере, предположим, что вы хотите обновить выполняемый файл с именем UPDATE. EXE, как только изменится один из исходных файлов. Предположим далее, что имена исходных файлов GETINPUT. C, FINDREC. C и UPDATE. C. Для создания файла описания утилиты MAKE, с помощью которого автоматически обновляется файл UPDATE. EXE, используйте следующую процедуру:
1. С помощьюя текстового редактора, создайте файл с именем UPDATE. Хотя файл описаний утилиты MAKE может иметь любое имя, может оказаться полезным присвоение файлу описаний то же самое имя, что и обрабатываемый файл (без расширения).
2. Введите имя обрабатываемого файла, за которям следует двоеточие, как показано ниже. Данный файл известен, как «выходной», поскольку утилита MAKE создает обновленную версию этого файла. (Выходные файлы также могут называться «целевыми»).
UPDATE. EXE:
3. Далее за двоеточием введите имена файлов, изменение которых может привести к изменению выходного файла. В нашем примере, вы должны обновить файл UPDATE. EXE, как только изменится один из файлов GETINPUT. C, FINDREC. C, UPDATE. C; строка файла описания в данном случае будет выглядеть следующим образом:
UPDATE. EXE: UPDATE. C GETINPUT. C FINDREC. C
UPDATE. EXE: UPDATE. C GETINPUT. C FINDREC. C #UPDATE ROUTINE 5. Если любой их входный файлов изменяется, введите команду, которую вы хотите выполнить. В данном примере предполагается, что вы хотите перекомпилировать и перекомпановать все входные файлы. В результате, файл описаний будет выглядеть следующим образом:
UPDATE. EXE:UPDATE. C GETINP. C FINDREC. C #UPDATE ROUTINE QCL UPDATE. C GETINPUT. C FINDREC. C
UPDATE. EXE:UPDATE. C GETINPUT. C FINDREC. C #UPDATE ROUTINE # RECOMPILE AND RELINK QCL UPDATE. C GETINPUT. C FINDREC. C
6. При выходе из редактора текстов сохраните файл описаний. Затем введите: MAKE
за которым следует имя файла описаний и нажмите ENTER. В нашем примере вам следует ввести:
MAKE UPDATE
7. Утилита MAKE сравнивает даты последней модификации каждого из входных файлов с датой выходного файла. Если все даты входных файлов «старее», чем дата выходного файла, утилита MAKE не производит никаких действий. Если же какой-либо входной файл «новее» по дате, чем выходной файл, утилита MAKE распознает, по отношению к какому входному файлу «устарел» выходной файл и, таким образом, выполняет команду, назначенную вами. В данном примере программа MAKE перекомпилирует исходные файлы и перекомпанует соответсвующие объектные файлы для создания нового файла UPDATE. EXE.