TweetFollow Us on Twitter

Uninstalling with AppleScript

Volume Number: 23 (2007)
Issue Number: 05
Column Tag: Scripting

Uninstalling with AppleScript

Building an uninstaller with AppleScript Studio

By José R.C. Cruz

Introduction

In a previous MacTech article, we learned how to use the PackageMaker tool to build a distribution package. We also learned how to localize that package for different languages, and how to customize it with scripts. But the one thing we were unable to do with the tool is to build an uninstaller.

Third-party tools such as ViseX and InstallerMaker can add an uninstall option to their installers. This feature is sadly missing from PackageMaker, though not without reason. In fact, most products are easy to remove -- they are contained in a single folder, and trashing that folder completely uninstalls the product. But some products will have multiple files installed in different directories. Others will create custom directories to store the files. A good example of such a product is Xcode. Its installer creates the custom directory Developer to contain its files. The installer also stores files in other directories such as /System/Library and /Library/Application Support. As a result, removing Xcode from the system can be a laborious process. In these situations, an uninstaller tool can be useful.

This article will demonstrate how to use AppleScript Studio to build an uninstaller. To get readers started on their own uninstallers, the Xcode project Uninstall is made available for downloading. A copy of this project can be obtained at the following URL: ftp://ftp.mactech.com/src/mactech/volume23_2007/23.05.sit.

The Receipts Bundle

After the Installer installs a software payload, it creates a copy of the package in the Receipts directory. The path to this directory is /Library/Receipts on the boot volume.

The copy of the installer package is known as a receipt bundle. Its presence indicates that a product has been installed successfully. It also tells the installer package if the latter has to do an upgrade, as opposed to an installation.

Figure 1 shows the internal structure of a typical receipt bundle. Notice that the bundle has most of the same files as an installer package. What is missing is the .paz.gz file containing the actual payload. Also missing are the two aliases to that file from the Resources subdirectory.


Figure 1. Structure of a typical receipts bundle.

There are software tools that purge the contents of the Receipts directory. This is often done to reclaim extra space, especially when the product associated with the receipt no longer exists. But removing a receipt, without removing the product, creates a new problem. Without the right receipt to guide it, an installer for a new product version may be unable to upgrade the current product correctly.

The BOM File

The BOM file is a list of all the files that comprise the software payload. It also defines the locations of each file on the target volume. This file is present in both the installer package and receipts bundle.

The BOM file format has its origins in the NeXTStep operating system. It is also a binary format and, as a result, is not directly readable. To read its contents, use the command-line tool lsbom to preprocess the BOM file.

The lsbom tool

The lsbom tool takes a BOM file as its input and renders its contents into human readable text. It then outputs the text to another file, or to stdout by default. The tool is a standard addition to the BSD subsystem of MacOS X. Its counterpart is the mkbom tool, which creates a BOM file for a given directory.

To use the lsbom tool, simply pass the path to the BOM file as its input. For example, to process the BOM file for the Sample.pkg receipt, type the following statement at the Terminal prompt.

   lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom

The tool will then parse the file and display its contents at lightning speed on the Terminal speed. To better read the output, pipe the results of the lsbom tool to the less tool.

   lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom | less

less will display the first N lines of text from lsbom. The number of lines displayed is dictated by the height of the Terminal window. To display the next N lines of text, tap on the Space bar. To display the previous N lines of text, tap on the B key while holding down the <CTRL> key.

Another way of handling the lsbom output is to save it to a file. To save the output to the file Sample.log, use the I/O redirection token '>'.

   lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom > Sample.log

Notice that, in both examples, the BOM file is always inside the Contents subdirectory of the receipt bundle. Also, the name of the BOM file is always Archive.bom. Most receipt bundles will follow the same conventions. Though it is possible for a BOM file to be located elsewhere in the bundle, this is rarely done.

The lsbom output

Listing 1 shows a sample output from the lsbom tool. Each entry corresponds to a file or directory installed by the package. The first three items of the BOM entry are arranged as follows.

directory_path file_modes user_id/group_id.

Each item is separated from the other by a single tab character (0x09). Now, if the entry is for a regular file, it will have two more items as shown below.

   directory_path file_modes user_id/group_id number_of_bytes crc_32

If it is for a symbolic link, its last item will be the path to the original file or directory.

   directory_path file_modes user_id/group_id number_of_bytes ¬
         original_path

Finally, if the entry is for a device file, its last item will be the assigned device number.

   directory_path file_modes user_id/group_id device_number

Listing 1. Sample output of the lsbom tool

.   40755   501/80
./Sample.app   40755   501/80
./Sample.app/Contents   40755   501/80
./Sample.app/Contents/Info.plist   100644   501/80   947 ¬
      1163649540
./Sample.app/Contents/MacOS   40755   501/80
./Sample.app/Contents/MacOS/Sample   100755   501/80   51956 ¬
      3193247409
./Sample.app/Contents/PkgInfo   100644   501/80   8 ¬
742937289
./Sample.app/Contents/Resources   40755   501/80
./Sample.app/Contents/Resources/Appearance.tiff   100644   501/80   4850 ¬
1276692542
...
./Sample.app/Contents/Resources/English.lproj   40755   501/80
./Sample.app/Contents/Resources/English.lproj/Credits.rtf   100644   501/80 ¬  
3163   3602318773
./Sample.app/Contents/Resources/English.lproj/Errors.strings   100644 ¬  
501/80   2978   2815210102
...

Most BOM file listings consist mostly of directories and regular files. Device files and symbolic links are seldom found. Also, the file_modes item is essentially the three permission flags written in octal form. Each of the lower three numbers represents the permission for world, group, and owner. The upper set of numbers represent the type of item in question. They are set to 40 for a directory, 100 for a generic file.

Notice that each directory_path item starts with a dot (.) character. This character is replaced by the IFPkgRelocatedPath value set in the Info.plist file. If that value is not set, the directory path is assumed to be relative to the OS X boot volume.

Also, if the package has installed payloads in other directories, the BOM listing will show these payloads. For example, if Sample.pkg has installed two files in the /usr/bin directory, the BOM listing may show these files as follows.

   ./usr/bin            40755      0/0
   ./usr/bin/foo      100755   0/0   12606   2275820725
   ./usr/bin/fubar      100755   0/0   12606   2275820725

Notice that both user_id and group_id items are set to 0 in the above example. This means that the owner of the two files and the directory is root. Removing the two files will require authentication. Do not, however, remove any directories or subdirectories with a root owner. Doing so may remove important files, and render the entire OS X platform unusable.

The lsbom options

The lsbom tool also provides a number of output options. Use these options to display specific entries from the BOM file as follows.

To display only the directories accessed or created during installation, use the -d option.

   lsbom -d /Library/Receipts/Sample.pkg/Contents/Archive.bom

The output listing will also include bundles such as .app, .bundle, and .lproj. To display only the paths of files that were installed or updated, use the -f option.

   lsbom -f /Library/Receipts/Sample.pkg/Contents/Archive.bom

To display only the paths of each directory and file, use the --s option.

   lsbom -s /Library/Receipts/Sample.pkg/Contents/Archive.bom

The lsbom tool also has options other than the ones shown above. To view a list of options, type the command lsbom -h at the Terminal prompt. Also, to view the tool's electronic manual, type info lsbom at the prompt.

AppleScript and the Shell

AppleScript is the native scripting language of the MacOS platform. First introduced in the 1990s, it is one of the first few languages that work in a GUI environment. It also uses a natural language syntax, which makes its scripts easy to read and write.

Another feature of AppleScript is that it can be extended using plug-ins. These plug-ins, or scripting additions, allow AppleScript to do tasks that are slow or impossible to do using the core language. The OS X version of AppleScript comes bundled with the plug-in named Standards Additions. With this plug-in, an AppleScript script can display simple dialogs and perform basic file I/O tasks. The script can also run Unix shell scripts using the do shell script function.

,b>The do shell script function

The do shell script function is AppleScript's gateway to the BSD subsystem of MacOS X. With this function, an AppleScript script can execute command-line tools or shell script files. It can also run a single-line shell script using this function. The function returns any results from the script as a string.

The function uses the interpreter set by the SHELL environment variable to do its tasks. To find out the current interpreter, launch the Script Editor tool, which is located in /Applications/AppleScripts. On the script window, type do shell script "printenv SHELL" and click on the Run button. If the current interpreter is bash, the function will return the string value of SHELL=/bin/bash on the Results pane.

Working with file paths

When using the do shell script function to manipulate files, it requires the file paths expressed using the POSIX format. In short, a forward slash character </> must separate each path name. For example, to parse the BOM file for Sample.pkg, pass the script to the function as follows.

   do shell script ¬
      "lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom"

Now if a path name contains any spaces, a reverse slash <\> character must precede each space. For example, to parse the BOM file for Test Sample.pkg, pass the script as follows.

   do shell script ¬
      "lsbom /Library/Receipts/Test\\ Sample.pkg/Contents/Archive.bom"

Notice that two reverse slashes precede the space in Test Sample.pkg. This is necessary due to a little quirk in AppleScript. The first reverse slash tells AppleScript to treat the second slash is part of the string. The second slash tells the shell interpreter to treat the space as part of the script text.

AppleScript, however, expresses its file paths using the MacOS format. Instead of a forward slash, each path name is separated by a colon <:> character. Also, each path name can contain spaces without the need for any reverse slashes. For example, the file path to the BOM file for Test Sample.pkg is written in MacOS format as follows.

   OS X:Library:Receipts:Test Sample.pkg:Contents:Archive.bom

Converting between file path formats can be quite tedious. To address this issue, the Standards Additions plug-in provides the POSIX file class. To convert the MacOS file path to Sample.pkg to the POSIX format, type the following statement in the Script Editor window.

   POSIX path of alias "OS X:Library:Receipts:Sample.pkg"

This will return the converted path as /Library/Receipts/Sample.pkg. To convert it back to a MacOS format, type the following on the editor window.

   POSIX file "/Library/Receipts/Sample.pkg"

Both examples have file paths set relative to the boot volume. Both also assume that the MacOS name of the boot volume is OS X. Now if a file path is set relative to a volume other than boot, the conversion will reflect that volume. For example, if the MacOS file path is set to Users:Applications:Public:, it will be /Volumes/Users/Applications/Public/ in POSIX format.

Authenticating a command

Some shell commands require authentication in order to perform their tasks. They are usually invoked in the Terminal window using the sudo command. For example, to create the subdirectory foo in /usr, type the following line at the Terminal prompt.

   sudo mkdir /usr/foo

The sudo command first prompts the user for an administrative password. When the correct password is entered, sudo then executes the mkdir command. Otherwise, it aborts after the user fails to enter the right password thrice in a row.

Using the sudo command through the do shell script function is both tedious and unnecessary. Instead, the function can authenticate the desired command by itself. For example, to create the same subdirectory shown above, type the following line on the Script Editor window.

   do shell script "mkdir /usr/foo" with administrator privileges

The function first prompts the user for a password using the dialog shown in Figure 2. Again, when the user enters the correct username and password, the function then executes the mkdir command. Otherwise, it aborts with an error message after the user fails to enter the right information three times in a row. The same also happens if the user clicks on the Cancel button.


Figure 2. The authentication dialog.

To use either approach, make sure that you have a user account with administrative privileges. To learn how to create such an account, consult one of the references listed at the end of this article.

Building with AppleScript Studio

There are many ways to build an uninstaller. One way is to build it as a shell script. One example is Xcode, which comes with a Perl script to uninstall its various components. This approach is easy to implement and test. It does, however, require the use of the Terminal window. It also provides very poor user interaction and feedback, if any.

Another way is to build the uninstaller as a Cocoa application. Cocoa gives the uninstaller a better way of interacting with the user. It also allows the uninstaller to perform tasks not possible with a shell command. But this approach requires too much resources and time to implement. It also has a very high learning curve.

A more practical way is to build the uninstaller as an AppleScript application. This is now easy to do with AppleScript Studio. The uninstaller gets a decent interface with which to interact with the user. It will be easy to build and test due to AppleScript's user-friendly syntax. This is the approach used for the Xcode project Uninstall.

Laying out the user interface

The Uninstall project has a single main window named Uninstall Demo. The window is subdivided into two panels by an NSTabView control. Both panels contain a single NSTableView control. The first table displays the contents of the Receipts directory (Figure 3). The second table displays the contents of the BOM file for the selected receipt (Figure 4).


Figure 3. The Uninstall window, Receipts panel.


Figure 4. The Uninstall window, Files panel.

The entire window layout is that of a basic Assistant. On the lower right corner are two pushbuttons, Prev and Next. The Next button is also set as the default button.

Both buttons are disabled by default. The Next button is enabled when the Receipts table has a selected entry. The Prev button is enabled when the current panel is the one with the Files table. Also, when the Files table has a selected entry, the Next button becomes the Uninstall button.

On the lower left corner of the window is the Cancel button. This button is set to respond to the <Esc> key. It also sends a performClose: message to the window when clicked.

Binding the widgets

The window and some of the controls are then bound to specific AppleScript handlers. The bindings are set in the AppleScript panel of the Show Inspector dialog (Figure 5). To display the dialog, choose Show Inspector from the Tools menu. Then select AppleScript from the drop-down list at the top of the dialog.


Figure 5. The Show Inspector dialog, AppleScript panel.

Table 1 is a list of the bindings set for each interface widget. The handlers shown in this table are all defined in the source file Uninstall.applescript. Notice that some widgets are bound to the same handlers. To identify which widget called the handler, check its name property. For instance, the following code fragment shows how to determine which button was clicked.

on clicked theObject
   local tBtn
   
   set tBtn to the (name of theObject) as string
   if (tBtn is equal to "prev") then
      -- the Previous button has been clicked
   else if (tBtn is equal to "next") then
      -- the Next button has been clicked
   end if -- (tBtn is equal to "prev")
end clicked -- theObject

Widget Name Class AppleScript Settings
Name Event Handler
Uninstall Demo NSWindow demo Nib awake from nib
Prev NSButton prev Action clicked
Next NSButton image/next Action clicked
Receipts NSTableView rcpt Nib awake from nib
Data View selection changed
Lists NSTableView list Nib awake from nib
Data View selection changed

Table 1. AppleScript settings for the Uninstall UI widgets.

Not shown in the table are the bindings for the application itself. To bind the application, select the File's Owner icon on the MainMenu.nib window. Then, from the Show Inspector dialog, click on the Application checkbox. Then set the bindings as shown in Figure 6.


Figure 6. Binding the AppleScript application.

Binding the Cancel button

On the other hand, the Cancel button is not bound to any AppleScript handler. Instead, it is bound directly to an action handler.

To set the binding, control-drag a line from the button to the main window. This will display the Show Inspector dialog with the Connections panel view active. Click on the Target/Action tab on the dialog. Then choose performClose: from the list of window actions (Figure 7).


Figure 7. Selecting the performClose: action.

The Quit Uninstall menu item is also bound in the same way. But this will be left as an exercise to the readers.

Building with Xcode

The Xcode project Uninstall contains three AppleScript source files. The Uninstall.applescript file has all the handlers called by the UI widgets. The Receipts.applescript file has the code to access the Receipts directory. Finally, the Files.applescript file has the code for processing the BOM file. It also has the code that will do the uninstall task.

For reasons of length, this article will only show code that is relevant and interesting. Readers can always view the entire source files by downloading the project from the MacTech website.

Accessing the Receipts directory

Shown in Listing 2 is the function handler that retrieves the contents of the Receipts directory. It takes a path to the directory as its input argument. It returns the results of the retrieval as a list of records.

First, the handler calls the list folder function to read the directory contents. The function responds by returning the contents as a list of filenames. Next, the handler parses each filename in the list. If the name belongs to a receipt bundle, the handler retrieves its bundle signature. Otherwise, the handler proceeds to the next name.

The handler uses the bundle signature to create a record together with the name. When done, it appends the record to the return list tPkg.

Listing 2. Retrieving a list of receipt bundles (Receipts.applescript).

property pRcptRec : {bnom:"", bsig:""}
to getBundles from aPath
   local tLst, tPkgs
   local tItem, tNom
   local isPkg
   
   -- read the contents of the directory
   set tLst to (list folder aPath)
   
   -- parse the list results
   set tPkgs to {}
   copy pRcptRec to tRec
   
   repeat with tNom in tLst
      -- prepare a path to a list item
      set tItem to aPath & ":" & tNom
      get info for file tItem
      
      -- is the item a bundle?
      set isPkg to package folder of result
      
      if (isPkg) then
         -- retrieve the bundle signature
         set tSig to (getBundleSignature for tItem)
         
         -- update the record template
         set bnom of tRec to tNom
         set bsig of tRec to tSig
         
         -- add the updated record to the list
         copy tRec to the end of tPkgs
      end if -- (isPkg)
   end repeat -- with tNom in tLst
   
   -- return the retrieval results
   return (tPkgs)
end getBundles -- from aPath

Reading the BOM file

Listing 3 shows the function handler used to convert the BOM file. It also shows how to use the do shell script function to call the lsbom tool. The handler takes a path to the receipt bundle as its input argument. If successful, it returns the file path to a temp file; otherwise, it returns an empty string.

First, the handler gets a path to the TemporaryItems directory. It converts the path to a POSIX formant, and appends the name of the temp file bom.out. This file will store the output results of the lsbom tool.

The handler then prepares the script to be executed with the do shell script function. The script consists of the file path to the BOM file, as well as the path to bom.out. For example, if the target receipt is Sample.pkg, the script will read as follows.

   lsbom --p fs /Library/Receipts/Sample.pkg/Contents/Archive.bom ¬ 
               > ~/Library/TemporaryFiles/bom.out

Note that, in actual practice, the entire script will consists only of a single line. It will also state the full path to the bom.out file on the user home directory.

Notice as well that a --p fs option is passed to the lsbom tool. This option tells the tool to display only the file paths and sizes of each BOM item. If the item happens to be a directory, its entry in the bom.out file will not have any size data.

Listing 3. Generating a BOM file for a given receipt (Files.applescript).

property pBOMPath : "/Contents/Archive.bom"
property pBOMTemp : "bom.out"
property pCmd : "lsbom "
property pOpts : "-p fs "
to getBOM for aRcpt
   local tTmp, tCmd
   
   -- retrieve a path to a temp directory
   set tTmp to path to temporary items from user domain
   set tTmp to POSIX path of tTmp
   
   -- prepare the output file path
   set tTmp to tTmp & "/" & pBOMTemp
   
   -- prepare the shell command
   set tCmd to pCmd & pOpts
   set tCmd to tCmd & aRcpt & pBOMPath
   set tCmd to tCmd & " > " & tTmp
   
   -- execute the shell command
   do shell script tCmd
   
   -- was it successful?
   try
      set tTmp to (POSIX file tTmp) as string
      alias tTmp
      return (tTmp)
   on error tErr number tTyp
      display dialog ("[FATAL]" & tErr as string)
      return ("")
   end try
end getBOM -- for aRcpt

Listing 4 shows the function handler used to parse the contents of the bom.out file. It takes the path to that file as its input argument. When done, it returns a list of records, each record representing a BOM entry.

The handler first opens a read-only access to the bom.out file. It reads all the entries in the file, and then closes the access.

The entries consist of a list of strings. Each entry alternates between the file path and size of a BOM item. The handler creates a BOM record for each entry. It then appends the record to the list variable tBOM, which is returned to the calling handler.

Listing 4. Reading the BOM file (Files.applescript).

property pBOMRec : {fnom:"", fsiz:""}
property pLF : 10
property pHT : 9
to loadBOMItems from theFile
   local tSrc, tSiz, tPos, tLen
   local tLst, tBOM, tDat, tRec, tNom
   local tTkn, tOdd
   
   -- initialize the following locals
   set tBOM to {}
   set tTkn to {}
   set tTkn to tTkn & (ASCII character pLF)
   set tTkn to tTkn & (ASCII character pHT)
   
   try
      -- start a read-only access to the file
      open for access theFile without write permission
      set tSrc to result
      if (tSrc > 0) then
         -- read the contents of the file
         read tSrc using delimiter tTkn
         set tLst to result
         
         -- close the read-only access to the file
         close access tSrc
      end if -- (tSrc > 0)
      
      -- parse the BOM entries
      copy pBOMRec to tRec
      set tLen to the length of tLst
      
      if (tLen > 0) then
         repeat with tPos from 1 to tLen by 2
            -- retrieve the following BOM items
            set tNom to item tPos of tLst
            set tSiz to item (tPos + 1) of tLst
            if (tSiz is equal to "") then
               set tSiz to "-1"
            end if -- (tSiz is equal to "")
            
            -- prepare the BOM record
            set fnom of tRec to (tNom as string)
            set fsiz of tRec to (tSiz as string)
            
            -- append the record to the return list
            copy tRec to the end of tBOM
         end repeat -- with tPos from 1 to tLen by 2
         
         -- remove the first two items
         set tLen to length of tBOM
         set tBOM to items 3 thru tLen of tBOM
end if -- (tSiz > 0)
   on error tErr
      -- something wrong has happened
      display dialog ("[FATAL] loadBOMItems:" & tErr as string)
   end try
   
   -- return a list of BOM entries
   return (tBOM)
end loadBOMItems -- theFile

Removing a BOM item

There are a many ways to remove a software product. The direct way is to locate the topmost directory from the BOM, and delete it together with its contents. Another way is to select specific items from the BOM for deletion. Choosing the right approach depends on the aim of the uninstaller. The Uninstall project, for instance, uses a variant of the second approach.

Shown in Listing 5 is the function handler that will remove a BOM item. It is called after the user selected an item from the Files listbox, and clicked on the Uninstall button.

The handler first creates an Uninstall folder in the TemporaryItems directory. Next, it moves the BOM item from its original path to the folder. It also deletes the item at the specified path. Once the handler completes its task, it returns a true to the calling handler. Otherwise, it returns a false if any errors occurred.

Listing 5. Removing a BOM item (Files.applescript).

   property pDirTrash : "Uninstall"
   to removeTheItem given path:aTgt, folder:aDir
      local tTmp, tBin, tCmd
      
      -- initialize the following locals
      set tTmp to path to temporary items from user domain as string
      set tBin to tTmp & pDirTrash
      
      -- create the temporary uninstall directory
      tell application "Finder"
         try
            if not (exists alias tBin) then
               make new folder at folder tTmp ¬
                  with properties {name:"Uninstall"}
            end if -- (exists alias tBin)
         on error tErr
            display dialog ¬
               "[FATAL] Failed to create the Uninstall directory"
            return false
         end try
      end tell -- application "Finder"
      
      -- attempt to remove the item
      tell application "Finder"
         try
            -- is the item a directory or a file?
            if (aDir) then -- it is a directory
               -- test delete the directory
               move folder aTgt to folder tBin with replacing
               delete folder aTgt
            else -- it is a file
               -- test delete the file
               move file aTgt to folder tBin with replacing
               delete file aTgt
            end if -- (aDir)
         on error tErr
            display dialog "[ERROR] " & tErr
            return false
         end try
      end tell -- application "Finder"
      
      -- the removal was successful
      return (true)
   end removeTheItem -- given path:aTgt, type:aTyp

Notice that the handler uses the Finder to delete the BOM item. While this works in most cases, it will fail if the item is inside a restricted directory such as /usr. For that case, replace the delete code with the following script statements.

   set aTgt to the POSIX path of alias aTgt
   set tCmd to "rm -Rf " & aTgt
   do shell script tCmd with administrator privileges

The above statements will prompt the user to validate the deletion that is about to occur.

Also, notice that the handler first makes a copy of the BOM item it is about to delete. This gives the user a chance to restore the deleted item back to its former location.

Final Thoughts

Product removal is just as important as product installation. Though most products are easy to remove manually, some require the use of an uninstaller tool. The tool will peruse the receipt package for the product, and delete all the files that belong to that product. This will help ensure that future products installations will be more successful.

AppleScript Studio makes it quite easy to build an uninstaller tool. It has a much lower learning curve compared to Cocoa. This alone makes for a faster build and deployment cycle. It allows the addition of a user-friendly interface, which is not possible through shell scripts.

Hopefully, this article helps to get you started in writing your own uninstaller. Until Apple adds an uninstall option to the Installer tool, writing your own is, for now, the next best solution.

Bibliography and References

Apple Computers. AppleScript Resources. Retrieved 2007 Feb 24. Online: http://www.apple.com/applescript/resources.

Apple Computers. "do shell script in AppleScript". Technical Note TN2065. Copyright 2003, 2005, 2006. Apple Computers, Inc.

Apple Computers. "Administrative Accounts". An Introduction to MacOS X Security for Web Developers. Copyright 2007. Apple Computers, Inc. 2004 Aug 25. Online: http://developer.apple.com/internet/security/securityintro.html

Apple Computers. "lsbom -- list contents of a bom file". Mac OS X Man Pages. Copyright 2003. Apple Computers, Inc. 2003 Apr 16. Online: http://developer.apple.com/documentation/Darwin/Reference/Manpages/man8/lsbom.8.html.


JC is a freelance engineering consultant and writer currently residing in North Vancouver, British Columbia. He divides his time between writing technical articles, and teaching origami at his local district's public library. He can be reached at anarakisware@cashette.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Firetask Pro 4.2.2 - Innovative task man...
Firetask Pro uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask Pro's "Today" view shows all... Read more
Bookends 13.4.3 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
LibreOffice 6.4.5.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Thunderbird 68.10.0 - Email client from...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Firefox 78.0.1 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
BetterTouchTool 3.389 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
Slack 4.7.0 - Collaborative communicatio...
Slack brings team communication and collaboration into one place so you can get more work done, whether you belong to a large enterprise or a small business. Check off your to-do list and move your... Read more
OsiriX Lite 11.0.3 - 3D medical image pr...
OsiriX Lite is an image processing software dedicated to DICOM images (".dcm" / ".DCM" extension) produced by medical equipment (MRI, CT, PET, PET-CT, ...) and confocal microscopy (LSM and BioRAD-PIC... Read more
Wireshark 3.2.5 - Network protocol analy...
Wireshark is one of the world's foremost network protocol analyzers, and is the standard in many parts of the industry. It is the continuation of a project that started in 1998. Hundreds of... Read more
Dabble 1.6.1 - Organize your manuscript,...
Dabble organizes your manuscript, story notes, and plot. Dabble simplifies the story, leaving more room in your brain to create, which is what being a writer is really about. Organize your story.... Read more

Latest Forum Discussions

See All

Pokemon Go's July Community Day wil...
Pokemon Go developers have announced the details concerning the upcoming Gastly Community Day. This particular event was selected by the players of the game after the Gas Pokemon came in second place after a poll that decided which Pokemon would... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Detective Di is a point-and-click murder...
Detective Di is a point-and-click murder mystery set in Tang Dynasty-era China. You'll take on the role of China's best-known investigator, Di Renjie, as he solves a series of grisly murders that will ultimately lead him on a collision course with... | Read more »
Dissidia Final Fantasy Opera Omnia is se...
Dissidia Final Fantasy Opera Omnia, one of Square Enix's many popular mobile RPGs, has announced a plethora of in-game events that are set to take place over the summer. This will include several rewards, Free Multi Draws and more. [Read more] | Read more »
Sphaze is a neat-looking puzzler where y...
Sphaze is a neat-looking puzzler where you'll work to guide robots through increasingly elaborate mazes. It's set in a visually distinct world that's equal parts fantasy and sci-fi, and it's finally launched today for iOS and Android devices. [... | Read more »
Apple Arcade is in trouble
Yesterday, Bloomberg reported that Apple is disappointed in the performance of Apple Arcade and will be shifting their approach to the service by focusing on games that can retain subscribers and canceling other upcoming releases that don't fit... | Read more »
Pixel Petz, an inventive platform for de...
Pixel Petz has built up a sizeable player base thanks to its layered, easy-to-understand creative tools and friendly social experience. It revolves around designing, trading, and playing with a unique collection of pixel art pets, and it's out now... | Read more »
The King of Fighters Allstar's late...
The King of Fighters ALLSTAR, Netmarble's popular action RPG, has once again been updated with a plethora of new content. This includes battle cards, events and 21 new fighters, which increases the already sizeable roster even more. [Read more] | Read more »
Romancing SaGa Re;univerSe, the mobile s...
Square Enix latest mobile spin-off Romancing SaGa Re;univerSe is available now globally for both iOS and Android. It initially launched in Japan back in 2018 where it's proven to be incredibly popular, so now folks in the West can finally see what... | Read more »
Away: Journey to the Unexpected is a sto...
Away: Journey to the Unexpected looks really quite lovely. Stylish, cute, and clearly heavily inspired by Japanese animation, it's amongst the best-looking mobile games on the horizon. Developed by a two-person team, this story-driven rogue-lite... | Read more »

Price Scanner via MacPrices.net

July 4th Sale: Woot offers wide range of Macs...
Amazon-owned Woot is blowing out a wide range of Apple Macs and iPads for July 4th staring at $279 and ranging up to just over $1000. Models vary from older iPads and 11″ MacBook Airs to some newer... Read more
Apple Pro Display XDR with Nano-Texture Glass...
Abt Electronics has Apple’s new 32″ Pro Display XDR model with the nano-texture glass in stock and on sale today for up to $144 off MSRP. Shipping is free: – Pro Display XDR (nano-texture glass): $... Read more
New 2020 Mac mini on sale for up to $100 off...
Amazon has Apple’s new 2020 Mac minis on sale today for $40-$100 off MSRP with prices starting at $759. Shipping is free: – 2020 4-Core Mac mini: $759 $40 off MSRP – 2020 6-Core Mac mini: $998.99 $... Read more
July 4th Sale: $100 off every 2020 13″ MacBoo...
Apple resellers have new 2020 13″ MacBook Airs on sale for $100 off Apple’s MSRP as part of their July 4th sales. Starting at $899, these are the cheapest new 2020 MacBooks for sale anywhere: (1) B... Read more
This hidden deal on Apple’s site can save you...
Are you a local, state, or federal government employee? If so, Apple offers special government pricing on their products, including AirPods, for you as well as immediate family members. Here’s how... Read more
Apple Watch Series 3 models on sale for new l...
Amazon has Apple Watch Series 3 GPS models on sale for $30 off MSRP, starting at only $169. Their prices are the lowest available for these models from any Apple reseller. Choose Amazon as the seller... Read more
Deal Alert! Get these refurbished 2018 13″ Ma...
Apple has restocked and lowered prices on select Certified Refurbished 2018 13″ MacBook Airs, starting at only $679. Each MacBook features a new outer case, comes with a standard Apple one-year... Read more
July 4th Sale: 13″ 2.0GHz MacBook Pros for $2...
B&H Photo has new 2020 13″ 2.0GHz MacBook Pros on sale for $200 off Apple’s MSRP as part of their July 4th sale. Prices start at $1599. These are the same MacBook Pros sold by Apple in their... Read more
July 1 only: $100 off Apple iPhone 11, 11 Pro...
Boost Mobile is offering Apple iPhone 11, 11 Pro, and iPhone 11 Pro Max models for $100 off MSRP with service. Their discount reduces the cost of an iPhone 11/64GB to $599, iPhone 11 Pro to $899 for... Read more
Apple offers $50-$100 Education discount on i...
Purchase a new 12.9″ or 11″ iPad Pro at Apple using your Education discount, and Apple will take $50-$100 off their MSRP. All teachers, students, and staff of any educational institution with a .edu... Read more

Jobs Board

Operating Room Assistant, *Apple* Hill Surg...
Operating Room Assistant, Apple Hill Surgical Center - Full Time, Day Shift, Monday - Saturday availability required Tracking Code 62363 Job Description Operating Read more
Perioperative RN - ( *Apple* Hill Surgical C...
Perioperative RN - ( Apple Hill Surgical Center) Tracking Code 60593 Job Description Monday - Friday - Full Time Days Possible Saturdays General Summary: Under the Read more
Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
*Apple* Mac Product Engineer - Barclays (Uni...
Apple Mac EngineerWhippany, NJ Support the development and delivery of solutions, products, and capabilities into the Barclays environment working across technical Read more
Blue *Apple* Cafe Student Worker - Pennsylv...
…enhance your work experience. Student positions are available at the Blue Apple Cafe. Employee meal discount during working hours. Duties include food preparation, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.