5 // Created by Claudio Bisegni on 29/07/09.
6 // Copyright 2009 Infn. All rights reserved.
9 #import "AFSBackgrounderDelegate.h"
10 #import "AFSMenuExtraView.h"
11 #import "AFSPropertyManager.h"
13 #import "TokenCredentialController.h"
14 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/fcntl.h>
19 #include <sys/errno.h>
24 @implementation AFSBackgrounderDelegate
25 #pragma mark NSApp Delegate
26 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
27 NSLog(@"Init the afs manager");
28 afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
29 // allocate the lock for concurent afs check state
30 tokensLock = [[NSLock alloc] init];
32 //remove the auto eanble on menu item
33 [backgrounderMenu setAutoenablesItems:NO];
34 //Sets the images in our NSStatusItem
38 // Get the imge for menu
39 //Load image for menu rappresentation
40 hasTokenImage = [self getImageFromBundle:@"hasToken"
43 noTokenImage = [self getImageFromBundle:@"noToken"
45 //get the sazi of the menu icon
46 menuSize = [hasTokenImage size];
47 //Start to read the afs path
48 [self readPreferenceFile:nil];
53 // Register for preference user change
54 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(readPreferenceFile:)
55 name:kAFSMenuExtraID object:kPrefChangeNotification];
57 // Register for afs state change
58 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(afsVolumeMountChange:)
59 name:kAFSMenuExtraID object:kMExtraAFSStateChange];
61 // Register for menu state change
62 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(chageMenuVisibility:)
63 name:kAFSMenuExtraID object:kMExtraAFSMenuChangeState];
65 //Register for mount/unmount afs volume
66 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
67 selector:@selector(afsVolumeMountChange:)
68 name:NSWorkspaceDidMountNotification object:nil];
70 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
71 selector:@selector(afsVolumeMountChange:)
72 name:NSWorkspaceDidUnmountNotification object:nil];
74 //try to see if we need tho show the menu at startup
76 [self setStatusItem:[showStatusMenu boolValue]];
78 NSLog(@"Check if we need to get token at login time %d", [aklogTokenAtLogin intValue]);
79 if([aklogTokenAtLogin boolValue] && afsState && !gotToken) {
80 NSLog(@"Proceed to get token");
81 //check if we must get the aklog at logint(first run of backgrounder
86 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
87 if(afsSysPath) [afsSysPath release];
92 if(hasTokenImage) [hasTokenImage release];
93 if(noTokenImage) [noTokenImage release];
95 // Unregister for preference change
96 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kPrefChangeNotification];
97 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSStateChange];
98 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSMenuChangeState];
99 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidMountNotification object:nil];
100 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidUnmountNotification object:nil];
103 // send notify that menuextra has closed
104 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kPrefChangeNotification];
106 if(tokensLock) [tokensLock release];
107 if(afsMngr) [afsMngr release];
108 return NSTerminateNow;
110 // -------------------------------------------------------------------------------
111 // -(void) readPreferenceFile
112 // -------------------------------------------------------------------------------
113 - (void) readPreferenceFile:(NSNotification *)notification
115 NSLog(@"Reading preference file");
117 [afsSysPath release];
120 CFPreferencesSynchronize((CFStringRef)kAfsCommanderID, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
121 CFPreferencesSynchronize((CFStringRef)kAfsCommanderID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
123 afsSysPath = PREFERENCE_AFS_SYS_PAT_STATIC;
125 // read the preference for aklog use
126 useAklogPrefValue = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_USE_AKLOG,
127 (CFStringRef)kAfsCommanderID,
128 kCFPreferencesCurrentUser,
129 kCFPreferencesAnyHost);
131 showStatusMenu = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_SHOW_STATUS_MENU,
132 (CFStringRef)kAfsCommanderID,
133 kCFPreferencesCurrentUser,
134 kCFPreferencesAnyHost);
136 aklogTokenAtLogin = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_AKLOG_TOKEN_AT_LOGIN, (CFStringRef)kAfsCommanderID,
137 kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
140 [self updateAfsStatus:nil];
143 // -------------------------------------------------------------------------------
144 // - (void)chageMenuVisibility:(NSNotification *)notification
145 // -------------------------------------------------------------------------------
147 - (void)chageMenuVisibility:(NSNotification *)notification {
148 NSLog(@"chageMenuVisibility");
149 [self readPreferenceFile:nil];
150 NSLog(@"showStatusMenu: %d", [showStatusMenu intValue]);
151 [self setStatusItem:[showStatusMenu boolValue]];
154 // -------------------------------------------------------------------------------
155 // - (void)startStopAfs:(id)sender
156 // -------------------------------------------------------------------------------
157 - (void)startStopAfs:(id)sender
159 NSLog(@"startStopAfs: %s",[afsSysPath UTF8String]);
160 if(!afsSysPath) return;
162 OSStatus status = noErr;
163 NSString *afsdPath = [TaskUtil searchExecutablePath:@"afsd"];
164 NSString *rootHelperApp = nil;
165 BOOL currentAfsState = NO;
168 if(afsdPath == nil) return;
169 currentAfsState = [afsMngr checkAfsStatus];
170 rootHelperApp = [[NSBundle mainBundle] pathForResource:@"afshlp" ofType:@""];
172 //[startStopScript setString: resourcePath];
173 //NSLog(@"LAunch repair HelperTool");
175 [self repairHelperTool];
177 // make the parameter to call the root helper app
178 status = [[AuthUtil shared] autorize];
182 //NSLog(@"Shutting down afs");
183 NSMutableString *afsKextPath = [[NSMutableString alloc] initWithCapacity:256];
184 [afsKextPath setString:afsSysPath];
185 [afsKextPath appendString:@"/etc/afs.kext"];
187 //NSLog(@"executeTaskWithAuth");
188 const char *stopAfsArgs[] = {"stop_afs", [afsKextPath UTF8String], [afsdPath UTF8String], 0L};
189 [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
193 //NSLog(@"Starting up afs");
194 const char *startAfsArgs[] = {[[ [NSBundle mainBundle] pathForResource:@"start_afs" ofType:@"sh"] UTF8String], [afsSysPath UTF8String], [afsdPath UTF8String], 0L};
195 [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
201 @catch (NSException * e) {
205 [[AuthUtil shared] deautorize];
206 [self updateAfsStatus:nil];
207 //Send notification to preferencepane
208 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kMenuExtraEventOccured];
213 // -------------------------------------------------------------------------------
215 // -------------------------------------------------------------------------------
216 - (void)getToken:(id)sender
220 globalRect.origin = [[[statusItem view] window] convertBaseToScreen:[[statusItem view] frame].origin];
221 globalRect.size = [[statusItem view] frame].size;
222 AFSPropertyManager *afsPropMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath ];
223 [afsPropMngr loadConfiguration];
226 if([useAklogPrefValue boolValue]) {
228 [afsPropMngr getTokens:false
231 [self klogUserEven:nil];
234 // register for user event
235 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
236 selector:@selector(klogUserEven:)
238 object:kLogWindowClosed];
240 credentialMenuController = [[AFSMenuCredentialContoller alloc] initWhitRec:globalRect
241 afsPropManager:afsPropMngr];
242 [credentialMenuController showWindow];
245 //Dispose afs manager
246 [afsPropMngr release];
249 // -------------------------------------------------------------------------------
250 // -(void) releaseToken
251 // -------------------------------------------------------------------------------
252 - (void)releaseToken:(id)sender
255 [self updateAfsStatus:nil];
259 // -------------------------------------------------------------------------------
260 // -(void) afsVolumeMountChange - Track for mount unmount afs volume
261 // -------------------------------------------------------------------------------
262 - (void) afsVolumeMountChange:(NSNotification *)notification{
263 [self updateAfsStatus:nil];
266 // -------------------------------------------------------------------------------
267 // -(void) updateAfsStatus
268 // -------------------------------------------------------------------------------
269 - (void)updateAfsStatus:(NSTimer*)timer
272 if(![tokensLock tryLock]) return;
274 // check the afs state in esclusive mode
275 afsState = [afsMngr checkAfsStatus];
277 NSArray *tokens = [afsMngr getTokenList];
278 gotToken = [tokens count] > 0;
281 //update the menu icon
282 [[statusItem view] setNeedsDisplay:YES];
287 // -------------------------------------------------------------------------------
288 // -(void) klogUserEven
289 // -------------------------------------------------------------------------------
290 -(void) klogUserEven:(NSNotification *)notification
292 if(credentialMenuController) {
293 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kLogWindowClosed];
294 [credentialMenuController closeWindow];
295 [credentialMenuController release];
296 credentialMenuController = nil;
298 //Send notification to PreferencePane
299 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kMenuExtraEventOccured];
301 [self updateAfsStatus:nil];
303 #pragma mark Operational Function
304 // -------------------------------------------------------------------------------
306 // -------------------------------------------------------------------------------
308 //start the time for check tokens validity
309 if(timerForCheckTokensList) return;
310 timerForCheckTokensList = [NSTimer scheduledTimerWithTimeInterval:TOKENS_REFRESH_TIME_IN_SEC
312 selector:@selector(updateAfsStatus:)
315 [timerForCheckTokensList fire];
318 // -------------------------------------------------------------------------------
320 // -------------------------------------------------------------------------------
322 if(!timerForCheckTokensList) return;
323 [timerForCheckTokensList invalidate];
324 timerForCheckTokensList = nil;
326 // -------------------------------------------------------------------------------
327 // -(void) getImageFromBundle
328 // -------------------------------------------------------------------------------
329 - (NSImage*)getImageFromBundle:(NSString*)fileName fileExt:(NSString*)ext
331 return [[NSImage alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName
336 // -------------------------------------------------------------------------------
337 // - (void)menuNeedsUpdate:(NSMenu *)menu
338 // -------------------------------------------------------------------------------
339 - (void)menuNeedsUpdate:(NSMenu *)menu {
340 if (menu == backgrounderMenu)
342 [startStopMenuItem setTitle:afsState?@"Shutdown AFS":@"Startup AFS"];
343 [getReleaseTokenMenuItem setTitle:gotToken?@"Release token":@"Get New Token"];
344 [getReleaseTokenMenuItem setEnabled:afsState];
345 [[statusItem view] setNeedsDisplay:YES];
351 // -------------------------------------------------------------------------------
352 // -(void) useAklogPrefValue
353 // -------------------------------------------------------------------------------
354 - (BOOL)useAklogPrefValue
356 if(useAklogPrefValue) return [useAklogPrefValue intValue] == NSOnState;
357 else return NSOffState;
360 // -------------------------------------------------------------------------------
362 // -------------------------------------------------------------------------------
363 - (void) repairHelperTool
368 NSLog(@"repairHelperTool");
369 NSString *afshlpPath = [[NSBundle mainBundle] pathForResource:@"afshlp" ofType:nil];
373 // Open tool exclusively, so nobody can change it while we bless it.
374 fdTool = open([afshlpPath UTF8String], O_NONBLOCK | O_RDONLY | O_EXLOCK, 0);
378 NSLog(@"Exclusive open while repairing tool failed: %d.", errno);
382 if(fstat(fdTool, &st))
384 NSLog(@"fstat failed.");
390 status = [[AuthUtil shared] autorize];
392 fchown(fdTool, 0, st.st_gid);
394 // Disable group and world writability and make setuid root.
395 fchmod(fdTool, (st.st_mode & (~(S_IWGRP | S_IWOTH)))/* | S_ISUID*/);
396 const char *args[] = {"root", [afshlpPath UTF8String],0L};
397 [[AuthUtil shared] execUnixCommand:"/usr/sbin/chown"
400 [[AuthUtil shared] deautorize];
402 } else NSLog(@"st_uid = 0");
408 NSLog(@"Self-repair done.");
412 #pragma mark accessor
413 // -------------------------------------------------------------------------------
415 // -------------------------------------------------------------------------------
416 -(NSStatusItem*)statusItem {
420 // -------------------------------------------------------------------------------
422 // -------------------------------------------------------------------------------
423 -(void)setStatusItem:(BOOL)show {
425 if(statusItem) return;
426 statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:menuSize.width] retain];
427 [statusItem setView:[[AFSMenuExtraView alloc] initWithFrame:[[statusItem view] frame]
429 menu:backgrounderMenu]];
430 //Tells the NSStatusItem what menu to load
431 [statusItem setMenu:backgrounderMenu];
432 //Sets the tooptip for our item
433 [statusItem setToolTip:@"OpenAFS Preference"];
434 //Enables highlighting
435 [statusItem setHighlightMode:YES];
436 [statusItem setImage:noTokenImage];
438 if(!statusItem) return;
439 [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
440 [statusItem autorelease];
444 // -------------------------------------------------------------------------------
445 // -(void) imageToRender
446 // -------------------------------------------------------------------------------
447 - (NSImage*)imageToRender
450 return hasTokenImage;
457 -(IBAction) startStopEvent:(id)sender {
458 [self startStopAfs:sender];
461 -(IBAction) getReleaseTokenEvent:(id)sender {
462 [self getToken:sender];