Ticket #11824: portstartupitem.tcl

File portstartupitem.tcl, 20.3 KB (added by markd@…, 17 years ago)
Line 
1# et:ts=4
2# portstartupitem.tcl
3#
4# $Id: portstartupitem.tcl 24156 2007-04-18 00:38:13Z jberry@macports.org $
5#
6# Copyright (c) 2004, 2005 Markus W. Weissman <mww@opendarwin.org>,
7# Copyright (c) 2005 Robert Shaw <rshaw@opendarwin.org>,
8# All rights reserved.
9#
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions are
12# met:
13#
14# 1. Redistributions of source code must retain the above copyright
15#    notice, this list of conditions and the following disclaimer.
16# 2. Redistributions in binary form must reproduce the above copyright
17#    notice, this list of conditions and the following disclaimer in the
18#    documentation and/or other materials provided with the distribution.
19# 3. Neither the name of Apple Computer, Inc. nor the names of its
20#    contributors may be used to endorse or promote products derived from
21#    this software without specific prior written permission.
22#
23# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34#
35
36
37#
38#       Newly added keys:
39#
40#       startupitem.executable  /path/executable
41#               The command to start an executable, this is exclusive of init, start, stop, restart
42#               This may be composed of exec arguments only--not shell code
43#
44#       startupitem.inetdcompat yes/no
45#               This can only be used with startupitem.executable and sets inetdCompatibility key
46#
47#       startupitem.inetdcompat.sockname        [socketname]
48#               Specify the xinetd socket servicename given in /etc/services, this is mandatory when
49#               using startupitem.inetdcomat, otherwise an invalid plist file results
50#   
51#       startupitem.inetdcompat.wait true/false
52#               This optional command can only be used with startupitem.inetdcompat, and corresponds
53#               to "wait" or "nowait" option of services in xinetd   
54#
55#       startupitem.pidfile             none
56#               There is no pidfile we can track
57#
58#       startupitem.pidfile             auto [filename.pid]
59#               The daemon is responsible for creating/deleting the pidfile
60#
61#       startupitem.pidfile             clean [filename.pid]
62#               The daemon creates the pidfile, but we must delete it
63#
64#       startupitem.pidfile             manual [filename.pid]
65#               We create and destroy the pidfile to track the pid we receive from the executable
66#
67#       startupitem.logfile             logpath
68#               Log to the specified file -- if not specified then output to /dev/null
69#               - for launchd, just set this as the standard out key
70#               - for systemstarter, redirect to this
71#
72#       startupitem.logevents   yes/no
73#               Log events to the log
74#               - for launchd, generate log messages inside daemondo
75#               - for systemstarter, generate log messages in our generated script
76#
77
78package provide portstartupitem 1.0
79package require portutil 1.0
80
81set_ui_prefix
82
83proc startupitem_create_rcng {args} {
84        global prefix destroot portname os.platform
85        global startupitem.name startupitem.requires
86        global startupitem.start startupitem.stop startupitem.restart
87        global startupitem.type
88
89        set scriptdir ${destroot}/${prefix}/etc/rc.d
90
91        if { ![exists startupitem.requires] } {
92                set startupitem.requires ""
93        }
94
95        # XXX We can't share defaults with startupitem_create_darwin
96        foreach item {startupitem.start startupitem.stop startupitem.restart} {
97                if {![info exists $item]} {
98                        return -code error "Missing required option $item"
99                }
100        }
101
102        file mkdir ${destroot} ${scriptdir}
103        set fd [open [file join ${scriptdir} ${startupitem.name}.sh] w 0755]
104
105        puts ${fd} "#!/bin/sh"
106        puts ${fd} "#"
107        puts ${fd} "# MacPorts generated RCng Script"
108        puts ${fd} "#"
109        puts ${fd} ""
110        puts ${fd} "# PROVIDE: ${startupitem.name}"
111        puts ${fd} "# REQUIRE: ${startupitem.requires}"
112        # TODO: Implement BEFORE support
113        puts ${fd} "# BEFORE:"
114        puts ${fd} "# KEYWORD: MacPorts"
115        puts ${fd} ""
116        puts ${fd} ". ${prefix}/etc/rc.subr"
117        puts ${fd} ""
118        puts ${fd} "name=\"${startupitem.name}\""
119        puts ${fd} "start_cmd=\"${startupitem.start}\""
120        puts ${fd} "stop_cmd=\"${startupitem.stop}\""
121        puts ${fd} "restart_cmd=\"${startupitem.restart}\""
122        puts ${fd} ""
123        puts ${fd} "load_rc_config \"${startupitem.name}\""
124        puts ${fd} ""
125        puts ${fd} "run_rc_command \"\$1\""
126        close ${fd}
127}
128
129proc startupitem_create_darwin_systemstarter {args} {
130        global UI_PREFIX prefix destroot destroot.keepdirs  portname os.platform
131        global startupitem.name startupitem.requires startupitem.init
132        global startupitem.start startupitem.stop startupitem.restart startupitem.executable
133        global startupitem.pidfile startupitem.logfile startupitem.logevents
134       
135        set scriptdir ${prefix}/etc/startup
136       
137        set itemname                    ${startupitem.name}
138        set uppername                   [string toupper ${startupitem.name}]
139        set itemdir                             /Library/StartupItems/${itemname}
140        set startupItemDir              ${destroot}${itemdir}
141        set startupItemScript   ${startupItemDir}/${itemname}
142        set startupItemPlist    ${startupItemDir}/StartupParameters.plist
143       
144        # Interpret the pidfile spec
145        #
146        # There are four cases:
147        #       (1) none (or none specified)
148        #       (2) auto [pidfilename]
149        #       (3) clean [pidfilename]
150        #       (4) manual [pidfilename]
151        #
152        set createPidFile false
153        set deletePidFile false
154        set pidFile ""
155        set pidfileArgCnt [llength ${startupitem.pidfile}]
156        if { ${pidfileArgCnt} > 0 } {
157                if { $pidfileArgCnt == 1 } {
158                        set pidFile "${prefix}/var/run/${itemname}.pid"
159                        lappend destroot.keepdirs "${destroot}${prefix}/var/run"
160                } else {
161                        set pidFile [lindex ${startupitem.pidfile} 1]
162                }
163                if { $pidfileArgCnt > 2 } {
164                        ui_error "$UI_PREFIX [msgcat::mc "Invalid parameter count to startupitem.pidfile: 2 expected, %d found" ${pidfileArgCnt}]"
165                }
166               
167                set pidStyle [lindex ${startupitem.pidfile} 0]
168                switch ${pidStyle} {
169                        none    { set createPidFile false; set deletePidFile false; set pidFile ""      }
170                        auto    { set createPidFile false; set deletePidFile false      }
171                        clean   { set createPidFile false; set deletePidFile true       }
172                        manual  { set createPidFile true;  set deletePidFile true       }
173                        default {
174                                ui_error "$UI_PREFIX [msgcat::mc "Unknown pidfile style %s presented to startupitem.pidfile" ${pidStyle}]"
175                        }
176                }
177        }
178
179        if { [llength ${startupitem.executable}] && 
180                        ![llength ${startupitem.init}] &&
181                        ![llength ${startupitem.start}] &&
182                        ![llength ${startupitem.stop}] &&
183                        ![llength ${startupitem.restart}] } {
184                # An executable is specified, and there is no init, start, stop, or restart
185        } else {
186                if { ![llength ${startupitem.start} ] } {
187                        set startupitem.start [list "sh ${scriptdir}/${portname}.sh start"]
188                }
189                if { ![llength ${startupitem.stop} ] } {
190                        set startupitem.stop [list "sh ${scriptdir}/${portname}.sh stop"]
191                }
192        }
193        if { ![llength ${startupitem.requires} ] } {
194                set startupitem.requires [list Disks NFS]
195        }
196        if { ![llength ${startupitem.logfile} ] } {
197                set startupitem.logfile "/dev/null"
198        }
199       
200        ########################
201        # Create the startup item directory
202        file mkdir ${startupItemDir}
203        file attributes ${startupItemDir} -owner root -group wheel
204       
205        ########################
206        # Generate the startup item script
207        set item [open "${startupItemScript}" w 0755]
208        file attributes "${startupItemScript}" -owner root -group wheel
209       
210        # Emit the header
211        puts ${item} {#!/bin/sh
212#
213# MacPorts generated StartupItem
214#
215
216}
217        puts ${item} "prefix=$prefix"
218        # Source the utilities package and the darwinports config file
219        puts ${item} {[ -r "/etc/rc.common" ] && . "/etc/rc.common"}
220        puts ${item} {[ -r "${prefix}/etc/rc.conf" ] && . "${prefix}/etc/rc.conf"}
221
222        # Emit the Configuration Section
223        puts ${item} "NAME=${itemname}"
224        puts ${item} "ENABLE_FLAG=\${${uppername}:=-NO-}"
225        puts ${item} "PIDFILE=\"${pidFile}\""
226        puts ${item} "LOGFILE=\"${startupitem.logfile}\""
227        puts ${item} "EXECUTABLE=\"${startupitem.executable}\""
228        puts ${item} ""
229        puts ${item} "HAVE_STARTCMDS=[expr [llength ${startupitem.start}] ? "true" : "false"]"
230        puts ${item} "HAVE_STOPCMDS=[expr [llength ${startupitem.stop}] ? "true" : "false"]"
231        puts ${item} "HAVE_RESTARTCMDS=[expr [llength ${startupitem.restart}] ? "true" : "false"]"
232        puts ${item} "DELETE_PIDFILE=${createPidFile}"
233        puts ${item} "CREATE_PIDFILE=${deletePidFile}"
234        puts ${item} "LOG_EVENTS=[expr [tbool ${startupitem.logevents}] ? "true" : "false"]"
235        puts ${item} ""
236
237        # Emit the init lines
238        foreach line ${startupitem.init} { puts ${item} ${line} }
239        puts ${item} ""
240       
241        # Emit the _Cmds
242        foreach kind { start stop restart } {
243                if {[llength [set "startupitem.$kind"]]} {
244                        puts ${item} "${kind}Cmds () {"
245                        foreach line [set "startupitem.$kind"] {
246                                puts ${item} "\t${line}"
247                        }
248                        puts ${item} "}\n"
249                }
250        }
251       
252        # vvvvv START BOILERPLATE vvvvvv
253        # Emit the static boilerplate section
254        puts ${item} {
255IsEnabled () {
256        [ "${ENABLE_FLAG}" = "-YES-" ]
257        return $?
258}
259
260CreatePIDFile () {
261        echo $1 > "$PIDFILE"
262}
263
264DeletePIDFile () {
265        rm -f "$PIDFILE"
266}
267
268ReadPID () {
269        if [ -r "$PIDFILE" ]; then
270                read pid < "$PIDFILE"
271        else
272                pid=0
273        fi
274        echo $pid
275}
276
277CheckPID () {
278        pid=$(ReadPID)
279        if (($pid)); then
280                kill -0 $pid >& /dev/null || pid=0
281        fi
282        echo $pid
283}
284
285NoteEvent () {
286        ConsoleMessage "$1"
287        $LOG_EVENTS && [ -n "$LOGFILE" ] && echo "$(date) $NAME: $1" >> $LOGFILE
288}
289
290StartService () {
291        if IsEnabled; then
292                NoteEvent "Starting $NAME"
293               
294                if $HAVE_STARTCMDS; then
295                        startCmds
296                elif [ -n "$EXECUTABLE" ]; then
297                        $EXECUTABLE &
298                        pid=$!
299                        if $CREATE_PIDFILE; then
300                                CreatePIDFile $pid
301                        fi
302                fi
303               
304        fi
305}
306
307StopService () {
308        NoteEvent "Stopping $NAME"
309       
310        gaveup=false
311        if $HAVE_STOPCMDS; then
312                # If we have stop cmds, use them
313                stopCmds
314        else           
315                # Otherwise, get the pid and try to stop the program
316                echo -n "Stopping $NAME..."
317               
318                pid=$(CheckPID)
319                if (($pid)); then
320                        # Try to kill the process with SIGTERM
321                        kill $pid
322                       
323                        # Wait for it to really stop
324                        for ((CNT=0; CNT < 15 && $(CheckPID); ++CNT)); do
325                                echo -n "."
326                                sleep 1
327                        done
328                       
329                        # Report status
330                        if (($(CheckPID))); then
331                                gaveup=true
332                                echo "giving up."
333                        else
334                                echo "stopped."
335                        fi
336                else
337                        echo "it's not running."
338                fi
339        fi
340       
341        # Cleanup the pidfile if we've been asked to
342        if ! $gaveup && $DELETE_PIDFILE; then
343                DeletePIDFile
344        fi
345}
346
347RestartService () {
348        if IsEnabled; then
349                NoteEvent "Restarting $NAME"
350               
351                if $HAVE_RESTARTCMDS; then
352                        # If we have restart cmds, use them
353                        restartCmds
354                else
355                        # Otherwise just stop/start it
356                        StopService
357                        StartService
358                fi
359               
360        fi
361}
362
363RunService "$1"
364}
365        # ^^^^^^ END BOILERPLATE ^^^^^^
366       
367        close ${item}
368       
369        ########################
370        # Generate the plist
371        set para [open "${startupItemPlist}" w 0644]
372        file attributes "${startupItemPlist}" -owner root -group wheel
373       
374        puts ${para} "\{"
375        puts ${para} "\tDescription\t= \"${itemname}\";"
376        puts ${para} "\tProvides\t= (\"${itemname}\");"
377        puts -nonewline ${para} "\tRequires\t= ("
378        puts -nonewline ${para} [format {"%s"} [join ${startupitem.requires} {", "}]]
379        puts ${para} ");"
380        puts ${para} "\tOrderPreference\t= \"None\";"
381        puts ${para} "\}"
382        close ${para}
383       
384        # Emit some information for the user
385        ui_msg "###########################################################"
386        ui_msg "# A startup item has been generated that will aid in"
387        ui_msg "# starting ${portname} with SystemStarter. It is disabled"
388        ui_msg "# by default. Add the following line to /etc/hostconfig"
389        ui_msg "# or ${prefix}/etc/rc.conf to start it at startup:"
390        ui_msg "#"
391        ui_msg "# ${uppername}=-YES-"
392        ui_msg "###########################################################"
393}
394
395proc startupitem_create_darwin_launchd {args} {
396        global UI_PREFIX prefix destroot destroot.keepdirs portname os.platform
397        global startupitem.name startupitem.requires startupitem.init
398        global startupitem.start startupitem.stop startupitem.restart startupitem.executable
399        global startupitem.pidfile startupitem.logfile startupitem.logevents
400        global startupitem.inetdcompat startupitem.inetdcompat.sockname
401        global startupitem.inetdcompat.nowait
402
403        set scriptdir ${prefix}/etc/startup
404       
405        set itemname            ${startupitem.name}
406        set uniquename          org.macports.${itemname}
407        set plistname           ${uniquename}.plist
408        set daemondest          LaunchDaemons
409        set itemdir                     ${prefix}/etc/${daemondest}/${uniquename}
410        set args                        [list \
411                                                        "${prefix}/bin/daemondo" \
412                                                        "--label=${itemname}" \
413                                                        ]
414       
415        file mkdir ${destroot}${itemdir}
416        file attributes ${destroot}${itemdir} -owner root -group wheel
417               
418        if { [llength ${startupitem.executable}] && 
419                        ![llength ${startupitem.init}] &&
420                        ![llength ${startupitem.start}] &&
421                        ![llength ${startupitem.stop}] &&
422                        ![llength ${startupitem.restart}] } {
423
424                # An executable is specified, and there is no init, start, stop, or restart
425                # code; so we don't need a wrapper script
426                set args [concat $args "--start-cmd" ${startupitem.executable} ";"]
427               
428        } else {
429       
430                # No executable was specified, or there was an init, start, stop, or restart
431                # option, so we do need a wrapper script
432               
433                set wrappername         ${itemname}.wrapper
434                set wrapper                     "${itemdir}/${wrappername}"
435
436                if { ![llength ${startupitem.start}] } {
437                        set startupitem.start [list "sh ${scriptdir}/${portname}.sh start"]
438                }
439                if { ![llength ${startupitem.stop}] } {
440                        set startupitem.stop [list "sh ${scriptdir}/${portname}.sh stop"]
441                }
442                if { ![llength ${startupitem.restart}] } {
443                        set startupitem.restart [list Stop Start]
444                }
445
446                lappend args \
447                        "--start-cmd"   ${wrapper} start   ";" \
448                        "--stop-cmd"    ${wrapper} stop    ";" \
449                        "--restart-cmd" ${wrapper} restart ";"
450
451                # Create the wrapper script
452                set item [open "${destroot}${wrapper}" w 0755]
453                file attributes "${destroot}${wrapper}" -owner root -group wheel
454
455                puts ${item} "#!/bin/sh"
456                puts ${item} "#"
457                puts ${item} "# MacPorts generated daemondo support script"
458                puts ${item} "#"
459                puts ${item} ""
460               
461                puts ${item} "#"
462                puts ${item} "# Init"
463                puts ${item} "#"
464                puts ${item} "prefix=$prefix"
465                foreach line ${startupitem.init}        { puts ${item} ${line} }
466                puts ${item} ""
467
468                puts ${item} "#"
469                puts ${item} "# Start"
470                puts ${item} "#"
471                puts ${item} "Start()"
472                puts ${item} "\{"
473                foreach line ${startupitem.start}       { puts ${item} "\t${line}" }
474                puts ${item} "\}"
475                puts ${item} ""
476               
477                puts ${item} "#"
478                puts ${item} "# Stop"
479                puts ${item} "#"
480                puts ${item} "Stop()"
481                puts ${item} "\{"
482                foreach line ${startupitem.stop}        { puts ${item} "\t${line}" }
483                puts ${item} "\}"
484                puts ${item} ""
485       
486                puts ${item} "#"
487                puts ${item} "# Restart"
488                puts ${item} "#"
489                puts ${item} "Restart()"
490                puts ${item} "\{"
491                foreach line ${startupitem.restart} { puts ${item} "\t${line}" }
492                puts ${item} "\}"
493                puts ${item} ""
494
495                puts ${item} "#"
496                puts ${item} "# Run"
497                puts ${item} "#"
498                puts ${item} "Run()"
499                puts ${item} "\{"
500                puts ${item} "case \$1 in"
501                puts ${item} "  start  ) Start   ;;"
502                puts ${item} "  stop   ) Stop    ;;"
503                puts ${item} "  restart) Restart ;;"
504                puts ${item} "  *      ) echo \"\$0: unknown argument: \$1\";;"
505                puts ${item} "esac"
506                puts ${item} "\}"
507                puts ${item} ""
508
509                puts ${item} "#"
510                puts ${item} "# Run a phase based on the selector"
511                puts ${item} "#"
512                puts ${item} "Run \$1"
513                puts ${item} ""
514
515                close ${item}
516        }
517               
518        # To log events then tell daemondo to log at verbosity=1
519        if { [tbool startupitem.logevents] } {
520                lappend args "--verbosity=1"
521        }
522       
523        # If pidfile was specified, translate it for daemondo.
524        #
525        # There are four cases:
526        #       (1) none
527        #       (2) auto [pidfilename]
528        #       (3) cleanup [pidfilename]
529        #       (4) manual [pidfilename]
530        #
531        set pidfileArgCnt [llength ${startupitem.pidfile}]
532        if { ${pidfileArgCnt} > 0 } {
533                if { $pidfileArgCnt == 1 } {
534                        set pidFile "${prefix}/var/run/${itemname}.pid"
535                        lappend destroot.keepdirs "${destroot}${prefix}/var/run"
536                } else {
537                        set pidFile [lindex ${startupitem.pidfile} 1]
538                }
539
540                if { ${pidfileArgCnt} > 2 } {
541                        ui_error "$UI_PREFIX [msgcat::mc "Invalid parameter count to startupitem.pidfile: 2 expected, %d found" ${pidfileArgCnt}]"
542                }
543               
544                # Translate into appropriate arguments to daemondo
545                set pidStyle [lindex ${startupitem.pidfile} 0]
546                switch ${pidStyle} {
547                        none    { lappend args "--pid=none" }
548                        auto    { lappend args "--pid=fileauto" "--pidfile" ${pidFile} }
549                        clean   { lappend args "--pid=fileclean" "--pidfile" ${pidFile} }
550                        manual  { lappend args "--pid=exec" "--pidfile" ${pidFile} }
551                        default {
552                                ui_error "$UI_PREFIX [msgcat::mc "Unknown pidfile style %s presented to startupitem.pidfile" ${pidStyle}]"
553                        }
554                }
555        } else {
556                if { [llength ${startupitem.executable}] } {
557                        lappend args "--pid=exec"
558                } else {
559                        lappend args "--pid=none"
560                }
561        }
562       
563        # Create the plist file
564        set plist [open "${destroot}${itemdir}/${plistname}" w 0644]
565       
566        puts ${plist} "<?xml version='1.0' encoding='UTF-8'?>"
567        puts ${plist} "<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN"
568        puts ${plist} "http://www.apple.com/DTDs/PropertyList-1.0.dtd >"
569        puts ${plist} "<plist version='1.0'>"
570        puts ${plist} "<dict>"
571       
572        puts ${plist} "<key>Label</key><string>${uniquename}</string>"
573       
574        puts ${plist} "<key>ProgramArguments</key>"
575        puts ${plist} "<array>"
576
577        if { [llength ${startupitem.inetdcompat}] } {
578                puts ${plist} "<string>${startupitem.executable}</string>"
579        } else {
580                foreach arg ${args} { puts ${plist} "\t<string>${arg}</string>" }
581        }
582
583        puts ${plist} "</array>"
584       
585        puts ${plist} "<key>Debug</key><false/>"
586        puts ${plist} "<key>Disabled</key><false/>"
587        puts ${plist} "<key>OnDemand</key><false/>"
588        puts ${plist} "<key>RunAtLoad</key><false/>"
589       
590        if { [llength ${startupitem.logfile}] } {
591                puts ${plist} "<key>StandardOutPath</key><string>${startupitem.logfile}</string>"
592        }
593       
594        if { [llength ${startupitem.inetdcompat}] } {
595
596        puts ${plist} "<key>inetdCompatibility</key>"
597        puts ${plist} "<dict>"
598        puts ${plist} "<key>Wait</key>"
599
600        if { [llength ${startupitem.inetdcompat.nowait}] } {
601        puts ${plist} "<false/>"
602        }
603
604        puts ${plist} "</dict>"
605        puts ${plist} "<key>InitGroups</key>"
606        puts ${plist} "<true/>"
607        puts ${plist} "<key>Sockets</key>"
608        puts ${plist} "<dict>"
609        puts ${plist} "<key>Listeners</key>"
610        puts ${plist} "<dict>"
611        puts ${plist} "<key>SockServiceName</key>"
612        puts ${plist} "<string>${startupitem.inetdcompat.sockname}</string>"
613        puts ${plist} "</dict>"
614        puts ${plist} "</dict>"
615        }
616
617        puts ${plist} "</dict>"
618        puts ${plist} "</plist>"
619
620        close ${plist}
621
622        # Make a symlink to the plist file
623        file mkdir "${destroot}/Library/${daemondest}"
624        system "cd ${destroot}/Library/${daemondest} && ln -sf ${itemdir}/${plistname}"
625       
626        # If launchd is not available, warn the user
627        set haveLaunchd ${portutil::autoconf::have_launchd}
628        if {![tbool haveLaunchd]} {
629                ui_msg "###########################################################"
630                ui_msg "# WARNING:"
631                ui_msg "# We're building a launchd startup item, but launchd wasn't"
632                ui_msg "# found by configure. Are you sure you didn't mess up your"
633                ui_msg "# ports.conf settings?"
634                ui_msg "###########################################################"
635        }
636       
637        # Emit some information for the user
638        ui_msg "###########################################################"
639        ui_msg "# A startup item has been generated that will aid in"
640        ui_msg "# starting ${portname} with launchd. It is disabled"
641        ui_msg "# by default. Execute the following command to start it,"
642        ui_msg "# and to cause it to launch at startup:"
643        ui_msg "#"
644        ui_msg "# sudo launchctl load -w /Library/${daemondest}/${plistname}"
645        ui_msg "###########################################################"
646}
647
648proc startupitem_create {args} {
649        global UI_PREFIX
650        global startupitem.type os.platform
651       
652        set startupitem.type [string tolower ${startupitem.type}]
653       
654        # Calculate a default value for startupitem.type
655        if {${startupitem.type} == "default" || ${startupitem.type} == ""} {
656                switch -exact ${os.platform} {
657                        darwin {
658                                set haveLaunchd ${portutil::autoconf::have_launchd}
659                                if { [tbool haveLaunchd] } {
660                                        set startupitem.type "launchd"
661                                } else {
662                                        set startupitem.type "systemstarter"
663                                }
664                        }
665                        default {
666                                set startupitem.type "rcng"
667                        }
668                }
669        }
670
671        ui_msg "$UI_PREFIX [msgcat::mc "Creating ${startupitem.type} control script"]"
672
673        switch -- ${startupitem.type} {
674                launchd                 { startupitem_create_darwin_launchd }
675                systemstarter   { startupitem_create_darwin_systemstarter }
676                rcng                    { startupitem_create_rcng }
677                default                 { ui_error "$UI_PREFIX [msgcat::mc "Unrecognized startupitem type %s" ${startupitem.type}]" }
678        }
679}