Рассмотрим пример запуска клиента Twitter вместе с любым пользователем системы. Да не просто запуск, а «назойливый» запуск, при котором Twitter будет самоперезапускаться всегда, даже после его завершения 🙂 И так, для начала нам нужно создать файл «сервиса» или «демона». Так как Twitter – это приложение с графической оболочкой не требующее привилегий администратора системы, то для него нужно создать именно сервис, а не демон, и покласть его в папку /Library/LaunchAgents (можно, конечно, его засунуть и в /System/Library/LaunchAgents, но так как там и так уйма системных служб, лучше этого не делать). Создадим файл следующего содержания:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>me.macdaily.twitter</string> <key>ProgramArguments</key> <array> <string>/Applications/Twitter.app/Contents/MacOS/Twitter</string> </array> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> </dict> </plist>
И сохраним его (пока) на Рабочем столе под именем me.macdaily.twitter.plist. Вообще имя может быть любым, главное – расширение .plist. Но обычно используют следующий формат:
com.companyname.appname.plist
где:
- companyname – это название компании, сайт или имя разработчика (и тому подобное);
- appname – соответственно, название приложения или службы.
Теперь разберём содержимое файла, а точнее его основные ключи и параметры:
<key>Label</key> <string>me.macdaily.twitter</string>
Ключ «Label» задаёт название сервиса, которое будет отображаться в Мониторинге системы или логах утилиты Консоль. В качестве параметра указывают (обычно) имя конфигурационного .plist файла, но без самого «.plist». Можно, конечно же, указать и другое название.
<key>ProgramArguments</key> <array> <string>/Applications/Twitter.app/Contents/MacOS/Twitter</string> </array>
Ключ «ProgramArguments» содержит массив, в котором указаны путь к исполняемому бинарному файлу (или bash/shell скрипту), и параметры его запуска. У клиента Twitter, впрочем как и у любого другого приложения для Mac OS X, исполняемый бинарный файл находится в каталоге Название программы.app/Contents/MacOS/. В этой папке может быть один или несколько бинарных исполняемых файлов (без расширений). Если в каталоге таких файлов оказалось несколько, то узнать какой именно из них «главный» можно подсмотрев параметр CFBundleExecutable в файле Info.plist (Название программы.app/Contents/Info.plist):
<key>CFBundleExecutable</key> <string>Twitter</string>
Из куска XML-кода видно, что у приложения Twitter.app исполняемым бинарным файлом является Twitter (он там, правда, один – трудно ошибиться). Кстати, если нужно запустить обычное приложение, например, браузер, плеер или какой-либо социальный клиент, то с прописыванием пути к исполняемому бинарному файлу можно не заморачиваться. Достаточно создать массив ссылаясь исключительно на само приложение, только при этом нужно указать параметр open, иначе launchd не поймёт, что мы от него хотим. На примере Twitter второй вариант запуска будет таким:
<key>ProgramArguments</key> <array> <string>open</string> <string>/Applications/Twitter.app</string> </array>
Для обычных приложений такой вариант более прост и понятен. Впрочем, мы пока разминаемся на Twitter, для которого не нужно никаких параметров загрузки, однако далее будут более интересные примеры.
<key>RunAtLoad</key> <true/>
Ключ «RunAtLoad» указывает системе, что правило нужно исполнить при загрузке ОС. То есть в нашем случае Twitter загрузится сразу же, как только любой пользователь войдёт в свою учётную запись. Параметр может принимать значения: true – запускать, false – не запускать. Если ключ «RunAtLoad» отсутствует – это будет приравниваться к значению false.
<key>KeepAlive</key> <true/>
Ключ «KeepAlive» со значением true указывает системе, что указанное в ключе «ProgramArguments» приложение должно быть всегда запущенно и с указанными в массиве параметрами. Если вручную завершить приложение, то система его автоматически запустит. Так будет до тех пор, пока служба принудительно не будет выгружена из памяти (ну или не будет удалён конфигурационный .plist и система не будет перезагружена).
Ну что, файл создан. Осталось переместить его в папку-назначение, поправить права доступа и атрибуты, и перезагрузиться. Запускаем Терминал и говорим системе, что мы работаем от root’а:
sudo -s
Перемещаем файл me.macdaily.twitter.plist в папку-назначение:
mv ~/Desktop/me.macdaily.twitter.plist /Library/LaunchAgents/
Правим права доступа:
chown root:wheel /Library/LaunchAgents/me.macdaily.twitter.plist
Правим атрибуты:
chmod 755 /Library/LaunchAgents/me.macdaily.twitter.plist
Перезагружаемся…
reboot
После очередной загрузки системы Twitter должен автоматом запуститься. А теперь попробуйте завершить его через Cmd ⌘ + Q. Ну как? Получилось? Интересно? – Ну тогда пойдём далее 😉
Большое спасибо за отличную статью!
С удовольствием слежу за вашими постами.
Привет, Эд! Спасибо за отзыв. Раз уж iOS-разработчик так считает, значит не всё так плохо, как мне казалось 🙂
Ну это вы зря, бетенька 🙂
Честно, очень полезные статейки и хорошо все написано и объяснено.
Не смотря на то, что я занимаюсь разработкой под iOS, но разница все-таки есть между настольной системой, хоть и не большая. Поэтому с удовольствием заполняю пробелы в знаниях, что бы позже еще писать софт и под Mac OS.
Желаю творческих успехов! 😉
Ну спасибо 🙂 Ждём тогда какую-либо новинку под Mac OS X by Eduard Shalumov 😀
Клятвенно обещаю, как что-то сделаю под взрослую систему (MacOS), сразу кину на MacDaily!
Кстати, когда начну разработку ПО под мак, может вместе программку сварганим?
Ну хорошо. Очень интересное предложение, у меня даже есть парочка идей 😉
Вот как славно! Я тогда маякну как начну под мак писать 😉
ОК, жду 😉
Спасибо! Очень познавательно и полезно!
Благодарю за отзыв. То есть продолжать в подобном духе всё-же стоит? 😉
Конечно!! Иначе мы жутко расстроимся 😉
Вы еще спрашиваете? =)
Конечно стоит!
Мне как новичку не понятно о чем речь, но как написано понравилось :). Буду следить за продолжением.
Спасибо 🙂
сапсибо, уважаемые
Всегда пожалуйста 😉
Здравствуйте Александр!
У меня следующая проблема:
Мне нужно что бы следующий shell script выполнялся при старте системы:
Я написал следующий XML:
В логах вижу следующее:
Что я делаю неправильно? Заранее благодарен за помощь!
Всё равно слетает (:
Поместите код между тегами <pre></pre>.
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0″>
<dict>
<key>Label</key>
<string>random-seed</string>
<key>ProgramArguments</key>
<array>
<string>echo “Initializing kernel random number generator…”</string>
<string>if</string>
<string>[ -f /var/random-seed ];</string>
<string>then</string>
<string>cat</string>
<string>/var/random-seed</string>
<string>></string>
<string>/dev/urandom</string>
<string>fi</string>
<string>dd</string>
<string>if=/dev/urandom</string>
<string>of=/var/random-seed</string>
<string>count=1</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
О! ОК, утром разберусь, а то спать охота 😉
Ну да, при конвертации shell-скриптов в XML могут возникнуть некоторые непонятки. Можно попробовать вставлять или целостный скрипт, типа:
Или вот так ещё можно попробовать:
Но самое проще (чтоб не манаться с «угадываниями») – создать bash-скрипт, например random-seed:
И в XML (.plist) указать к созданному скрипту полный путь:
Естественно, скрипту random-seed нужно будет присвоит соответствующие права доступа и атрибуты.
Громадное Спасибо, попробовал последний вариант – вроде всё получилось ( в логах поиск строки random-seed ничего не находится – это правильно?)
И второй вопрос – Вы не знаете как сделать что бы скрипт выполнялся при ВЫХОДЕ из системы?
Ответе пожалуйста!
Да не за что. Проверить, отрабатывает ли скрипт, можно следующим способом. У вас в скрипте есть строка:
Но так как это echo будет запускаться через launchd то в Консоль ничего выводиться не будет (кроме ошибок). Модифицируйте скрипт таким образом:
И теперь все echo будут выводиться в Консоль. После перезагрузки запустите консоль и поищите слово «RandomSeed» или строку «Initializing kernel random number generator» в логах. Если они присутствуют – всё ОК, скрипт отрабатывает. Этот финт я использую как своего рода инструмент для отладки 😉
По поводу выполнения скриптов перед выходом/выключением/перезагрузкой… До версии 10.4 Tiger, и включая её, была очень простая возможность исполнять любое множество криптов, просто поместив их в соответствующую папку. С выходом следующих версий Mac OS X этот принцип изминили, и в текущих 10.7 Lion и 10.8 Mountain Lion для запуска logout-скриптов необходимо использовать хук. Работает это так:
1. Создадим shell-скрипт с нужными командами, например вот такой:
2. Сохраним его, к примеру, в системной папке /sbin под именем logout_hook и назначим ему правильные права доступа и атрибуты:
3. Теперь добавим хук:
Ну и попробуем… Я сам-то не пробовал, но, по идее, всё должно заработать.
Спасибо! Вроде всё работает!
Пожалуйста 😉
Оказывается я рано радовался:
—————————————–
Jun 16 22:08:01 MacBook.local loginwindow[343]: *** NSTask: Task create for path ‘/bin/customs_cripts/random-seed_Stop’ failed: 22, “Invalid argument”. Terminating temporary process.
—————————————–
random-seed_Stop:
=======================
LOGS=’RandomSeedStop’
(
echo “RandomSeedStop and I logout now…”
say -v Milena “Я Random Seed Stop, Я завершаю работу…”
# Сохранить источник случайности для генератора случайных чисел
# при завершении работы. Сохранить 512 байт, которые составляют
# пул энтропии для генератора случайных чисел.
echo “Saving random seed…”
dd if=/dev/urandom of=/var/random-seed count=1
) | logger -s -t $LOGS
=======================
Кто виноват и Что делать???
Покажите содержимое скрипта.
Так я же выше его привёл:
Во-первых, где #!/bin/bash вначале?
Во-вторых, если голосовые компоненты Milena будут отсутствовать в система – будет ошибка.
Лучше сделать так:
Огромное Вам спасибо за помощь и долготерпение!
Все получилось – виноват был отсутствующий #!/bin/bash
Не за что 😉 Рад, что у вас всё вышло 🙂
Здравствуйте, это опять я.
После обновления до 10.9.2 в консоли для RandomSeedStart (см.выше) вот такое сообщение:
20.03.14 1:33:57,305 locationd[73]: NBB-Could not get UDID for stable refill timing, falling back on random
Как это исправить?
Приветствую! Я догадался, что это снова вы 😉
Сложный вопрос… Проверил у себя – у меня всё работает (тоже 10.9.2). Я не совсем понимаю суть фразы «NBB-Could not get UDID for stable refill timing, falling back on random», но, по-моему, там идётся речь о том, что не получается получить UDID за определённый (выделенный) промежуток времени.
Попробуйте для начала при помощи Дисковой утилиты сделать проверку/восстановления диска (не прав доступа, а именно диска): Дисковая утилита → выбираете весь накопитель целиком → Первая помощь → Исправить диск. Потом сделайте то же самое для системного раздела (Macintosh HD). Для проверки/восстановления системного раздела, скорее всего, придётся загрузиться с Recovery HD. Отпишитесь, пожалуйста, о результатах 😉
Отписываюсь – ничего не изменилось.
На всякий случай вот файл.
Так это всего-лишь файл для автозапуска скрипта. У вас, судя по всему, скрипт отрабатывает правильно, проблема не в автозапуске, и не в скрипте. Проблема в том, что утилита dd не может вытянуть UDID из /dev/urandom, который, скорее всего, используется для генерации.
Подскажите пожалуйста, если сталкивались. Есть сервер слушающий порт принимающий запросы и отправляющий ответы. При простом запуске под пользователем работает всегда без проблем. Прекрасно запускается в виде демона из любого каталога при старте системы. Диагностика показывает что все работает как надо, порт открыт. По безопасности порт открыт, но принимать соединения отказывается. Клиент не видит его. В нормальный рабочий режим переходит только если его снять и его снова поднимет launchd. Дальше проблем больше не возникает. В plist’e прописывал sockets по мануалу, но тогда клиенты зависают намертво, а сервер соединения все равно не видит и не принимает. Перезапуск в данном поведении ничего не меняет.
Буду признателен за любую наводку так как в сети ничего найти пока не получилось. Да и применение Sockets разделов практически не рассматривается. Но точно знаю что есть ограничения по портам. Но опять же, какие…
Доброго дня, подскажите что это за процесс, как его убить, RunOuc , в поиске не могу прогуглить, когда он запущен “кушает 90%” процессора, mac book air ^ при этом греется сильно, и батарея быстро садиться, после перезагрузки на какое то время пропадает, а потом может опять появиться…
Спасибо заранее…
Приветствую! Нужно смотреть. Это процесс автозагрузки (по моему). То есть что-то после старта системы должно было запуститься, но оно зависло и «кушает» проц.
Добрый день. У меня выскочила вот такая ошибка. Делал действия на странице 2.
2014-09-25 22:31:19.259 Net Monitor[629:507] *** WARNING: -[NSImage compositeToPoint:operation:] is deprecated in MacOSX 10.8 and later. Please use -[NSImage drawAtPoint:fromRect:operation:fraction:] instead.
Программа не запускатся, и не перезапускается. Скрипт, полная копия вашего со второй страницы, только изменен путь к другому файлу.
Простите что без уточнения. У меня не запускается все в автоматическом режиме. И на данный момент у меня Maveriks 10.9.5