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"
46 //Start to read the afs path
47 [self readPreferenceFile:nil];
52 // Register for preference user change
53 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(readPreferenceFile:)
54 name:kAFSMenuExtraID object:kPrefChangeNotification];
56 // Register for afs state change
57 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(afsVolumeMountChange:)
58 name:kAFSMenuExtraID object:kMExtraAFSStateChange];
60 // Register for menu state change
61 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(chageMenuVisibility:)
62 name:kAFSMenuExtraID object:kMExtraAFSMenuChangeState];
64 //Register for mount/unmount afs volume
65 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
66 selector:@selector(afsVolumeMountChange:)
67 name:NSWorkspaceDidMountNotification object:nil];
69 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
70 selector:@selector(afsVolumeMountChange:)
71 name:NSWorkspaceDidUnmountNotification object:nil];
73 //try to see if we need tho show the menu at startup
75 [self setStatusItem:[showStatusMenu boolValue]];
77 NSLog(@"Check if we need to get token at login time %d", [aklogTokenAtLogin intValue]);
78 if([aklogTokenAtLogin boolValue] && afsState && !gotToken) {
79 NSLog(@"Proceed to get token");
80 //check if we must get the aklog at logint(first run of backgrounder
85 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
86 if(afsSysPath) [afsSysPath release];
91 if(hasTokenImage) [hasTokenImage release];
92 if(noTokenImage) [noTokenImage release];
94 // Unregister for preference change
95 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kPrefChangeNotification];
96 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSStateChange];
97 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSMenuChangeState];
98 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidMountNotification object:nil];
99 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidUnmountNotification object:nil];
102 // send notify that menuextra has closed
103 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kPrefChangeNotification];
105 if(tokensLock) [tokensLock release];
106 if(afsMngr) [afsMngr release];
107 return NSTerminateNow;
109 // -------------------------------------------------------------------------------
110 // -(void) readPreferenceFile
111 // -------------------------------------------------------------------------------
112 - (void) readPreferenceFile:(NSNotification *)notification
114 NSLog(@"Reading preference file");
116 [afsSysPath release];
119 CFPreferencesSynchronize((CFStringRef)kAfsCommanderID, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
120 CFPreferencesSynchronize((CFStringRef)kAfsCommanderID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
122 afsSysPath = PREFERENCE_AFS_SYS_PAT_STATIC;
124 // read the preference for aklog use
125 useAklogPrefValue = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_USE_AKLOG,
126 (CFStringRef)kAfsCommanderID,
127 kCFPreferencesCurrentUser,
128 kCFPreferencesAnyHost);
130 showStatusMenu = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_SHOW_STATUS_MENU,
131 (CFStringRef)kAfsCommanderID,
132 kCFPreferencesCurrentUser,
133 kCFPreferencesAnyHost);
135 aklogTokenAtLogin = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_AKLOG_TOKEN_AT_LOGIN, (CFStringRef)kAfsCommanderID,
136 kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
139 [self updateAfsStatus:nil];
142 // -------------------------------------------------------------------------------
143 // - (void)chageMenuVisibility:(NSNotification *)notification
144 // -------------------------------------------------------------------------------
146 - (void)chageMenuVisibility:(NSNotification *)notification {
147 NSLog(@"chageMenuVisibility");
148 [self readPreferenceFile:nil];
149 NSLog(@"showStatusMenu: %d", [showStatusMenu intValue]);
150 [self setStatusItem:[showStatusMenu boolValue]];
153 // -------------------------------------------------------------------------------
154 // - (void)startStopAfs:(id)sender
155 // -------------------------------------------------------------------------------
156 - (void)startStopAfs:(id)sender
158 NSLog(@"startStopAfs: %s",[afsSysPath UTF8String]);
159 if(!afsSysPath) return;
161 OSStatus status = noErr;
162 NSString *afsdPath = [TaskUtil searchExecutablePath:@"afsd"];
163 NSString *rootHelperApp = nil;
164 BOOL currentAfsState = NO;
167 if(afsdPath == nil) return;
168 currentAfsState = [afsMngr checkAfsStatus];
169 rootHelperApp = [[NSBundle mainBundle] pathForResource:@"afshlp" ofType:@""];
171 //[startStopScript setString: resourcePath];
172 //NSLog(@"LAunch repair HelperTool");
174 [self repairHelperTool];
176 // make the parameter to call the root helper app
177 status = [[AuthUtil shared] autorize];
181 //NSLog(@"Shutting down afs");
182 NSMutableString *afsKextPath = [[NSMutableString alloc] initWithCapacity:256];
183 [afsKextPath setString:afsSysPath];
184 [afsKextPath appendString:@"/etc/afs.kext"];
186 //NSLog(@"executeTaskWithAuth");
187 const char *stopAfsArgs[] = {"stop_afs", [afsKextPath UTF8String], [afsdPath UTF8String], 0L};
188 [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
192 //NSLog(@"Starting up afs");
193 const char *startAfsArgs[] = {[[ [NSBundle mainBundle] pathForResource:@"start_afs" ofType:@"sh"] UTF8String], [afsSysPath UTF8String], [afsdPath UTF8String], 0L};
194 [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
200 @catch (NSException * e) {
204 [[AuthUtil shared] deautorize];
205 [self updateAfsStatus:nil];
206 //Send notification to preferencepane
207 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kMenuExtraEventOccured];
212 // -------------------------------------------------------------------------------
214 // -------------------------------------------------------------------------------
215 - (void)getToken:(id)sender
219 globalRect.origin = [[[statusItem view] window] convertBaseToScreen:[[statusItem view] frame].origin];
220 globalRect.size = [[statusItem view] frame].size;
221 AFSPropertyManager *afsPropMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath ];
222 [afsPropMngr loadConfiguration];
225 if([useAklogPrefValue boolValue]) {
227 [afsPropMngr getTokens:false
230 [self klogUserEven:nil];
233 // register for user event
234 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
235 selector:@selector(klogUserEven:)
237 object:kLogWindowClosed];
239 credentialMenuController = [[AFSMenuCredentialContoller alloc] initWhitRec:globalRect
240 afsPropManager:afsPropMngr];
241 [credentialMenuController showWindow];
244 //Dispose afs manager
245 [afsPropMngr release];
248 // -------------------------------------------------------------------------------
249 // -(void) releaseToken
250 // -------------------------------------------------------------------------------
251 - (void)releaseToken:(id)sender
254 [self updateAfsStatus:nil];
258 // -------------------------------------------------------------------------------
259 // -(void) afsVolumeMountChange - Track for mount unmount afs volume
260 // -------------------------------------------------------------------------------
261 - (void) afsVolumeMountChange:(NSNotification *)notification{
262 [self updateAfsStatus:nil];
265 // -------------------------------------------------------------------------------
266 // -(void) updateAfsStatus
267 // -------------------------------------------------------------------------------
268 - (void)updateAfsStatus:(NSTimer*)timer
271 if(![tokensLock tryLock]) return;
273 // check the afs state in esclusive mode
274 afsState = [afsMngr checkAfsStatus];
276 NSArray *tokens = [afsMngr getTokenList];
277 gotToken = [tokens count] > 0;
284 // -------------------------------------------------------------------------------
285 // -(void) klogUserEven
286 // -------------------------------------------------------------------------------
287 -(void) klogUserEven:(NSNotification *)notification
289 if(credentialMenuController) {
290 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kLogWindowClosed];
291 [credentialMenuController closeWindow];
292 [credentialMenuController release];
293 credentialMenuController = nil;
295 //Send notification to PreferencePane
296 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kMenuExtraEventOccured];
298 [self updateAfsStatus:nil];
300 #pragma mark Operational Function
301 // -------------------------------------------------------------------------------
303 // -------------------------------------------------------------------------------
305 //start the time for check tokens validity
306 if(timerForCheckTokensList) return;
307 timerForCheckTokensList = [NSTimer scheduledTimerWithTimeInterval:TOKENS_REFRESH_TIME_IN_SEC
309 selector:@selector(updateAfsStatus:)
312 [timerForCheckTokensList fire];
315 // -------------------------------------------------------------------------------
317 // -------------------------------------------------------------------------------
319 if(!timerForCheckTokensList) return;
320 [timerForCheckTokensList invalidate];
321 timerForCheckTokensList = nil;
323 // -------------------------------------------------------------------------------
324 // -(void) getImageFromBundle
325 // -------------------------------------------------------------------------------
326 - (NSImage*)getImageFromBundle:(NSString*)fileName fileExt:(NSString*)ext
328 return [[NSImage alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName
333 // -------------------------------------------------------------------------------
334 // - (void)menuNeedsUpdate:(NSMenu *)menu
335 // -------------------------------------------------------------------------------
336 - (void)menuNeedsUpdate:(NSMenu *)menu {
337 if (menu == backgrounderMenu)
339 [startStopMenuItem setTitle:afsState?@"Shutdown AFS":@"Startup AFS"];
340 [getReleaseTokenMenuItem setTitle:gotToken?@"Release token":@"Get New Token"];
341 [getReleaseTokenMenuItem setEnabled:afsState];
342 [[statusItem view] setNeedsDisplay:YES];
348 // -------------------------------------------------------------------------------
349 // -(void) useAklogPrefValue
350 // -------------------------------------------------------------------------------
351 - (BOOL)useAklogPrefValue
353 if(useAklogPrefValue) return [useAklogPrefValue intValue] == NSOnState;
354 else return NSOffState;
357 // -------------------------------------------------------------------------------
359 // -------------------------------------------------------------------------------
360 - (void) repairHelperTool
365 NSLog(@"repairHelperTool");
366 NSString *afshlpPath = [[NSBundle mainBundle] pathForResource:@"afshlp" ofType:nil];
370 // Open tool exclusively, so nobody can change it while we bless it.
371 fdTool = open([afshlpPath UTF8String], O_NONBLOCK | O_RDONLY | O_EXLOCK, 0);
375 NSLog(@"Exclusive open while repairing tool failed: %d.", errno);
379 if(fstat(fdTool, &st))
381 NSLog(@"fstat failed.");
387 status = [[AuthUtil shared] autorize];
389 fchown(fdTool, 0, st.st_gid);
391 // Disable group and world writability and make setuid root.
392 fchmod(fdTool, (st.st_mode & (~(S_IWGRP | S_IWOTH)))/* | S_ISUID*/);
393 const char *args[] = {"root", [afshlpPath UTF8String],0L};
394 [[AuthUtil shared] execUnixCommand:"/usr/sbin/chown"
397 [[AuthUtil shared] deautorize];
399 } else NSLog(@"st_uid = 0");
405 NSLog(@"Self-repair done.");
409 #pragma mark accessor
410 // -------------------------------------------------------------------------------
412 // -------------------------------------------------------------------------------
413 -(NSStatusItem*)statusItem {
417 // -------------------------------------------------------------------------------
419 // -------------------------------------------------------------------------------
420 -(void)setStatusItem:(BOOL)show {
422 if(statusItem) return;
423 statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
424 [statusItem setView:[[AFSMenuExtraView alloc] initWithFrame:[[statusItem view] frame]
426 menu:backgrounderMenu]];
427 //Tells the NSStatusItem what menu to load
428 [statusItem setMenu:backgrounderMenu];
429 //Sets the tooptip for our item
430 [statusItem setToolTip:@"OpenAFS Preference"];
431 //Enables highlighting
432 [statusItem setHighlightMode:YES];
433 [statusItem setImage:noTokenImage];
435 if(!statusItem) return;
436 [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
437 [statusItem autorelease];
441 // -------------------------------------------------------------------------------
442 // -(void) imageToRender
443 // -------------------------------------------------------------------------------
444 - (NSImage*)imageToRender
447 return hasTokenImage;
454 -(IBAction) startStopEvent:(id)sender {
455 [self startStopAfs:sender];
458 -(IBAction) getReleaseTokenEvent:(id)sender {
459 [self getToken:sender];