Mac OS X

Dealing with ._ files in Mac OS X

by Matt Danger on Jan.26, 2010, under Mac OS X, Shell Scripting, terminal

The current code base I’m working from is located on a network share and controlled by Subversion. I’ve been dealing with the Apple Double format problem a lot lately and scripted a simple clean up solution.

For those unfamiliar with the Apple Double problem, it is an old bug that exists from the early days of Mac OS X. Here’s the explanation from the Apple Knowledge Base:

Before Mac OS X, the Mac OS used ‘forked’ files, which have two components: a data fork and a resource fork. The Mac OS Standard (HFS) and Mac OS Extended (HFS Plus) disk formats support forked files. When you move these types of files to other disk formats, the resource fork can be lost.

With Mac OS X, there is a mechanism called “Apple Double” that allows the system to work with disk formats that do not have a forked file feature, such as remote NFS, SMB, WebDAV directories, or local UFS volumes. Apple Double does this by converting the file into two separate files. The first new file keeps the original name and contains the data fork of the original file. The second new file has the name of the original file prefixed by a “._ ” and contains the resource fork of the original file. If you see both files, the ._ file can be safely ignored. Sometimes when deleting a file, the ._ component will not be deleted. If this occurs you can safely delete the ._ file.

Essentially, when you’re working on files located on a network share you end up with duplicates of the file with a “._” prefix. The files are empty and are quite the annoyance. They are removed when the network share is unmounted. However, I leave my share mounted for long periods of time and the files make a mess of my Subversion status reports.

You can run the following command to clean the files up.

find . -name '._*' -exec rm '{}' ';'

You could also make this into a launchctl or cron task. Happy hacking!

Leave a Comment : more...

Scripting Login Tasks in Mac OS X

by Matt Danger on Jan.21, 2009, under Mac OS X, terminal

Recently I wanted to configure some of our lab computers to automatically configure printers when a user logged on. While reading Apple’s documentation to find a solution I learned about the possible ways to script login procedures in Mac OS X 10.5.

Login Hooks

The first method of scripting a login action is the use of a Login Hook. A Login Hook is a script that is executed immediately after the user logs on but before other login processes are performed. The script runs as root and needs to be chmod’d +x to be made executable. This feature has existed in OS X for some time and is handy for some account specific tasks.

To configure OS X to run your script run the following command as root in Terminal:

defaults write com.apple.loginwindow LoginHook /path/to/script 

This modifies root’s login window properties in /var/root/Library/Preferences/. In Leopard login hooks do not work in any other user or system-wide com.apple.loginwindow preference file. I’m not sure if they did in previous versions.

More information about LoginHooks can be found on Apple’s developer site.

System Login Items (Deprecated)

SystemLoginItems was an old login script mechanism that has now been deprecated and will be removed in Snow Leopard. Scripts were executed when the Login Window was displayed and ran as root. When a user logged in the script died and was executed again as the user.

In Leopard SystemLoginItems behaves oddly. Applications do not launch upon login, instead they launch when the user logs out and attempt to run behind the Login Window.

Example usage of SystemLoginItems:

defaults write /Library/Preferences/com.apple.SystemLoginItems AutoLaunchedApplicationDictionary -array-add '{ "Path" = "/path/to/script"; "Hide" = 0; }'

SystemLoginItems was not well documented by Apple and it’s believed Apple created them specifically for a few developers. Now that Launchd exists SystemLoginItems is no longer necessary, likely the reason it is to be removed.

A brief discussion of SystemLoginItems can be found in this MacEnterprise thread.

Global Login Items

GlobalLoginItems has superseded SystemLoginItems, and in some cases LoginHooks, as the best method for launching a login script. Unlike LoginHooks, a Global Login Item executes after all the login processes have completed and is meant for GUI applications. You can even configure whether you would like the application’s GUI to appear or not.

To configure a Global Login Item run the following command as root:

defaults write /Library/Preferences/loginwindow AutoLaunchedApplicationDictionary -array-add '{ "Path" = "/path/to/script"; "Hide" = "0"; }'

To remove the global login item either delete /Library/Preferences/loginwindow or run the following command as root:

defaults delete /Library/Preferences/loginwindow AutoLaunchedApplicationDictionary

Note that we are modifying the loginwindow.plist file and not the more popular com.apple.loginwindow.plist file. A reboot may also be required after deleting a global login item

More information about Login Items can be found in this Apple Technical Note.

Leave a Comment :, , , , , , , more...

Sudo without a password in Mac OS X

by Matt Danger on Jan.12, 2009, under Mac OS X, terminal

Mac OS X users who spend a lot of time in Terminal may find having to enter their account passwords when using sudo to be inconvenient. A few simple steps can disable this and allow you to use sudo without ever needing a password in Mac OS X 10.5 Leopard. The steps are similar for 10.3 and 10.4 however /etc/sudoers may be slightly different.

Warning! Be aware that removing the password requirement to use sudo eliminates a level of security. If someone gains access to your account they will be able to easily escalate to root privileges.

First, edit /etc/sudoers and uncomment (remove the “#”)

# %wheel ALL=(ALL) NOPASSWD: ALL

Then, in Terminal run the following command as root, replacing your_username with your account username:

dscl . append /Groups/wheel GroupMembership your_username

Leave a Comment more...

Adjust Mac OS X display brightness from the Terminal

by Matt Danger on Dec.17, 2008, under Mac OS X, Uncategorized

One of the classrooms I maintain is comprised of 2.4Ghz iMacs (MB323LL/A) that are dual booted with Windows XP and Mac OS X. Sometimes when the workstations are restarted from XP to OS X the display brightness gets changed to its dim power saver setting. This requires the user manually increase the display brightness by pressing the F2 key, which is inconvenient. I haven’t been able to determine the cause of this issue so I wanted to create a login hook to increases the brightness as a temporary fix.

OS X doesn’t ship with a command line utility that let’s you change display brightness. Fortunately, Nicholas Riley has written a utility that uses OS X frameworks to accomplish this quickly and easily. Here’s the code:

#include <stdio.h>
#include <unistd.h>
#include <IOKit/graphics/IOGraphicsLib.h>
#include <ApplicationServices/ApplicationServices.h>
 
const int kMaxDisplays = 16;
const CFStringRef kDisplayBrightness = CFSTR(kIODisplayBrightnessKey);
const char *APP_NAME;
 
void errexit(const char *fmt, ...) {
  va_list ap;
  va_start(ap, fmt);
  fprintf(stderr, "%s: ", APP_NAME);
  vfprintf(stderr, fmt, ap);
  fprintf(stderr, "\n");
  exit(1);
}
 
void usage() {
  fprintf(stderr, "usage: %s [-m|-d display] [-v] <brightness>\n", APP_NAME);
  fprintf(stderr, "   or: %s -l [-v]\n", APP_NAME);
  exit(1);
}
 
int main(int argc, char * const argv[]) {
  APP_NAME = argv[0];
  if (argc == 1)
    usage();
 
  int verbose = 0;
  unsigned long displayToSet = 0;
  enum { ACTION_LIST, ACTION_SET_ALL, ACTION_SET_ONE } action = ACTION_SET_ALL;
  extern char *optarg;
  extern int optind;
  int ch;
 
  while ( (ch = getopt(argc, argv, "lmvd:")) != -1) {
    switch (ch) {
    case 'l':
      if (action == ACTION_SET_ONE) usage();
      action = ACTION_LIST;
      break;
    case 'v':
      verbose = 1;
      break;
    case 'm':
      if (action != ACTION_SET_ALL) usage();
      action = ACTION_SET_ONE;
      displayToSet = (unsigned long)CGMainDisplayID();
      break;
    case 'd':
      if (action != ACTION_SET_ALL) usage();
      action = ACTION_SET_ONE;
      errno = 0;
      displayToSet = strtoul(optarg, NULL, 0);
      if (errno == EINVAL || errno == ERANGE)
	errexit("display must be an integer index (0) or a hexadecimal ID (0x4270a80)");
      break;
    default: usage();
    }
  }
 
  argc -= optind;
  argv += optind;
 
  float brightness;
  if (action == ACTION_LIST) {
    if (argc > 0) usage();
  } else {
    if (argc != 1) usage();
 
    errno = 0;
    brightness = strtof(argv[0], NULL);
    if (errno == ERANGE)
      usage();
    if (brightness < 0 || brightness > 1)
      errexit("brightness must be between 0 and 1");
  }
 
  CGDirectDisplayID display[kMaxDisplays];
  CGDisplayCount numDisplays;
  CGDisplayErr err;
  err = CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays);
  if (err != CGDisplayNoErr)
    errexit("cannot get list of displays (error %d)\n", err);
 
  CFWriteStreamRef stdoutStream = NULL;
  if (verbose) {
    CFURLRef devStdout =
      CFURLCreateWithFileSystemPath(NULL, CFSTR("/dev/stdout"),
				    kCFURLPOSIXPathStyle, false);
    stdoutStream = CFWriteStreamCreateWithFile(NULL, devStdout);
    if (stdoutStream == NULL)
      errexit("cannot create CFWriteStream for /dev/stdout");
    if (!CFWriteStreamOpen(stdoutStream))
      errexit("cannot open CFWriteStream for /dev/stdout");
  }								  
 
  for (CGDisplayCount i = 0; i < numDisplays; ++i) {
    CGDirectDisplayID dspy = display[i];
    CFDictionaryRef originalMode = CGDisplayCurrentMode(dspy);
    if (originalMode == NULL)
      continue;
 
    if (action == ACTION_LIST) {
      printf("display %d: ", i);
      if (CGMainDisplayID() == dspy)
	printf("main display, ");
      printf("ID 0x%x\n", (unsigned int)dspy);
      if (verbose) {
	CFStringRef error = NULL;
	CFPropertyListWriteToStream(originalMode, stdoutStream,
				    kCFPropertyListXMLFormat_v1_0, &error);
	if (error != NULL)
	  errexit("failed to write display info (%s)",
		  CFStringGetCStringPtr(error,
					CFStringGetFastestEncoding(error)));
      }
    }
 
    io_service_t service = CGDisplayIOServicePort(dspy);
    switch (action) {
    case ACTION_SET_ONE:
      if ((CGDirectDisplayID)displayToSet != dspy && displayToSet != i)
	continue;
    case ACTION_SET_ALL:
      err = IODisplaySetFloatParameter(service, kNilOptions, kDisplayBrightness,
				       brightness);
      if (err != kIOReturnSuccess) {
	fprintf(stderr,
		"%s: failed to set brightness of display 0x%x (error %d)",
		APP_NAME, (unsigned int)dspy, err);
	continue;
      }
      if (!verbose) continue;
    case ACTION_LIST:
      err = IODisplayGetFloatParameter(service, kNilOptions, kDisplayBrightness,
				       &brightness);
      if (err != kIOReturnSuccess) {
	fprintf(stderr,
		"%s: failed to get brightness of display 0x%x (error %d)",
		APP_NAME, (unsigned int)dspy, err);
	continue;
      }
      printf("display %d: brightness %f\n", i, brightness);
    }
  }
 
  return 0;
}

You can compile your own utility by saving this code to a file named brightness.c and doing:

gcc -std=c99 -o brightness brightness.c -framework IOKit -framework ApplicationServices

You can also download the precompiled binary.

You can create a login hook to automatically increase the brightness by chmoding the downloaded ‘brightness’ file to 755 and running the following command as root in Terminal:

defaults write com.apple.loginwindow LoginHook "/path/to/brightness 1"

8 Comments :, , more...

A few Mac OS X tweaks you might not have known about

by Matt Danger on Dec.15, 2008, under Mac OS X

I’m a die hard Mac OS X user and also a lab administrator at a college. Over the years I’ve found several tweaks that help me configure both my personal computer and lab workstations to do different tasks.

Force the printer icon to auto quit after a print job completes. Right-click on the icon and select “Auto Quit” or do:
defaults write /Users/yourusername/Library/Preferences/com.apple.print.PrintingPrefs "Quit When Finished" -bool true

Disable disk checksum verification
defaults write com.apple.frameworks.diskimages skip-verify true

Gradient highlights for Stacks
defaults write com.apple.dock mouse-over-hilte-stack -boolean true

Add recent applications as a Stack on Dock
defaults write com.apple.dock persistent-others -array-add '{ "tile-data" = { "list-type" = 1; }; "tile-type" = "recents-tile"; }

Make extended print dialog show by default
defaults write -g PMPrintingExpandedStateForPrint -bool true

Change the current screenshot format
defaults write com.apple.screencapture type jpg

Disable iTunes store arrows
defaults write com.apple.iTunes show-store-arrow-links -bool false

Stop Safari “saved text” dialogs
defaults write com.apple.Safari DebugConfirmTossingUnsubmittedFormText NO

Force Safari to open all links in new tab
defaults write com.apple.Safari TargetedClicksCreateTabs -bool true

Disable application crash dialogs
defaults write com.apple.CrashReporter DialogType none

Make hidden Dock icons transparent
defaults write com.apple.Dock showhidden -bool true

Disable Dashboard
defaults write com.apple.dashboard mcx-disabled -boolean true

Stop disk image verification
defaults write com.apple.frameworks.diskimages skip-verify true

Enable Data Detectors in 10.5 iChat
defaults write com.apple.iChat EnableDataDetectors true

Modify Sheet Animation
defaults write NSGlobalDomain NSWindowResizeTime .001

Login window tweaks

The text underneath the “Mac OS X” title of the login window will change if you click on it. You can configure the login window to display any of these as default. Valid options are HostName, SystemVersion, SystemBuild, SerialNumber, IPAddress, DSStatus, or Time
defaults write /Library/Preferences/com.apple.loginwindow AdminHostInfo Time

You can add a message to the login window. This is useful in a lab environment when you need to give instructions to your users.
defaults read /Library/Preferences/com.apple.loginwindow LoginwindowText "Some custom message."

Leave a Comment :, , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Send me a message on AIM!

Friends

Read what I read...