/* Platform isolation convenience functions */ /* * Argyll Color Correction System * * Author: Graeme W. Gill * Date: 28/9/97 * * Copyright 1997 - 2013 Graeme W. Gill * All rights reserved. * * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :- * see the License2.txt file for licencing details. */ #include #include #include #include #include #include #ifdef NT # if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501 # define _WIN32_WINNT 0x0501 # endif # define WIN32_LEAN_AND_MEAN # include #include #include #include #endif #if defined(UNIX) #include #include #include #include #include #include #include #include /* select() defined, but not poll(), so emulate poll() */ #if defined(FD_CLR) && !defined(POLLIN) #include "pollem.h" #define poll_x pollem #else #include /* Else assume poll() is native */ #define poll_x poll #endif #endif #ifndef SALONEINSTLIB #include "copyright.h" #include "aconfig.h" #else #include "sa_config.h" #endif #include "numsup.h" #include "xspect.h" #include "insttypes.h" #include "conv.h" #include "icoms.h" #ifdef UNIX_APPLE //#include #include #include #include #include #include #include #include #include #include #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 # include #endif #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 # include #endif #endif /* UNIX_APPLE */ #undef DEBUG #ifdef DEBUG # define DBG(xx) a1logd(g_log, 0, xx ) # define DBGA g_log, 0 /* First argument to DBGF() */ # define DBGF(xx) a1logd xx #else # define DBG(xx) # define DBGF(xx) #endif #ifdef __BORLANDC__ #define _kbhit kbhit #endif /* ============================================================= */ /* MS WINDOWS */ /* ============================================================= */ #ifdef NT /* wait for and then return the next character from the keyboard */ /* (If not_interactive, return getchar()) */ int next_con_char(void) { int c; if (not_interactive) { HANDLE stdinh; char buf[1]; DWORD bread; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { return 0; } /* Ignore end of line characters */ for (;;) { if (ReadFile(stdinh, buf, 1, &bread, NULL) && bread == 1 && buf[0] != '\r' && buf[0] != '\n') { return buf[0]; } } } c = _getch(); return c; } #ifdef NEVER // Don't need this now. /* Horrible hack to poll stdin when we're not interactive. */ /* This has the drawback that the char and returm must be */ /* written in one operation for the character to be recognised - */ /* trying to do this manually typically doesn't work unless you are */ /* very fast and lucky. */ static int th_read_char(void *pp) { char *rp = (char *)pp; HANDLE stdinh; char buf[1]; DWORD bread; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { *rp = 0; /* We've started */ return 0; } *rp = 0; /* We've started */ if (ReadFile(stdinh, buf, 1, &bread, NULL) && bread == 1 && buf[0] != '\r' && buf[0] != '\n') { *rp = buf[0]; } return 0; } #endif /* NEVER */ /* If there is one, return the next character from the keyboard, else return 0 */ /* (If not_interactive, always returns 0) */ int poll_con_char(void) { if (not_interactive) { /* Can't assume that it's the console */ #ifdef NEVER // Use better approach below. athread *getch_thread = NULL; volatile char c = 0xff; /* This is pretty horrible. The problem is that we can't use */ /* any of MSWin's async file read functions, because we */ /* have no way of ensuring that the STD_INPUT_HANDLE has been */ /* opened with FILE_FLAG_OVERLAPPED. Used a thread instead... */ /* ReOpenFile() would in theory fix this, but it's not available in WinXP, only Visa+, */ /* and aparently doesn't work on stdin anyway! :-( */ if ((getch_thread = new_athread(th_read_char, (char *)&c)) != NULL) { HANDLE stdinh; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { return 0; } /* Wait for the thread to start */ while (c == 0xff) { Sleep(10); /* We just hope 1 msec is enough for the thread to start */ } Sleep(10); /* Give it time to read */ CancelIo(stdinh); /* May not work since ReadFile() is on a different thread ? */ getch_thread->del(getch_thread); return c; } #else /* ! NEVER */ /* This approach is very flakey from the console, but seems */ /* to work reliably when operated progromatically. */ HANDLE stdinh; char buf[10] = { 0 }, c; DWORD bread; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { return 0; } // printf("Waiting\n"); if (WaitForSingleObject(stdinh, 1) == WAIT_OBJECT_0) { // printf("stdin signalled\n"); // FlushFileBuffers(stdinh); // FlushConsoleInputBuffer(stdinh); if (ReadFile(stdinh, buf, 1, &bread, NULL)) { int i; // fprintf(stderr,"Read %d chars 0x%x 0x%x 0x%x\n",bread,buf[0],buf[1], buf[2]); if (buf[0] != '\r' && buf[0] != '\n') return buf[0]; return 0; } } #endif /* !NEVER */ return 0; } /* Assume it's the console */ if (_kbhit() != 0) { int c = next_con_char(); return c; } return 0; } /* Suck all characters from the keyboard */ /* (If not_interactive, does nothing ?) */ void empty_con_chars(void) { if (not_interactive) { HANDLE stdinh; char buf[100] = { 0 }, c; DWORD bread; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) return; for (;;) { if (WaitForSingleObject(stdinh, 1) == WAIT_OBJECT_0) { ReadFile(stdinh, buf, 100, &bread, NULL); } else { break; } } return; } Sleep(50); /* _kbhit seems to have a bug */ while (_kbhit()) { if (next_con_char() == 0x3) /* ^C Safety */ break; } } /* Sleep for the given number of seconds */ void sleep(unsigned int secs) { Sleep(secs * 1000); } static athread *beep_thread = NULL; static int beep_delay; static int beep_freq; static int beep_msec; /* Delayed beep handler */ static int delayed_beep(void *pp) { msec_sleep(beep_delay); a1logd(g_log,8, "msec_beep activate\n"); Beep(beep_freq, beep_msec); return 0; } /* Activate the system beeper */ void msec_beep(int delay, int freq, int msec) { a1logd(g_log,8, "msec_beep %d msec\n",msec); if (delay > 0) { if (beep_thread != NULL) beep_thread->del(beep_thread); beep_delay = delay; beep_freq = freq; beep_msec = msec; if ((beep_thread = new_athread(delayed_beep, NULL)) == NULL) a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n"); } else { a1logd(g_log,8, "msec_beep activate\n"); Beep(freq, msec); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ int acond_timedwait_imp(HANDLE cond, CRITICAL_SECTION *lock, int msec) { int rv; LeaveCriticalSection(lock); rv = WaitForSingleObject(cond, msec); EnterCriticalSection(lock); if (rv == WAIT_TIMEOUT) return 1; if (rv != WAIT_OBJECT_0) return 2; return 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #ifdef NEVER /* Not currently needed, or effective */ /* Set the current threads priority */ int set_interactive_priority() { if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) == 0) return 1; return 0; } int set_normal_priority() { if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL) == 0) return 1; return 0; } #endif /* NEVER */ #undef USE_BEGINTHREAD /* Wait for the thread to exit. Return the result */ static int athread_wait(struct _athread *p) { if (p->finished) return p->result; WaitForSingleObject(p->th, INFINITE); return p->result; } /* Destroy the thread */ static void athread_del( athread *p ) { DBG("athread_del called\n"); if (p == NULL) return; if (p->th != NULL) { if (!p->finished) { DBG("athread_del calling TerminateThread() because thread hasn't finished\n"); TerminateThread(p->th, (DWORD)-1); /* But it is worse to leave it hanging around */ } CloseHandle(p->th); } free(p); } /* _beginthread doesn't leak memory, but */ /* needs to be linked to a different library */ #ifdef USE_BEGINTHREAD /* Thread function */ static void __cdecl threadproc( void *lpParameter ) { #else DWORD WINAPI threadproc( LPVOID lpParameter ) { #endif athread *p = (athread *)lpParameter; p->result = p->function(p->context); p->finished = 1; #ifdef USE_BEGINTHREAD #else return 0; #endif } athread *new_athread( int (*function)(void *context), void *context ) { athread *p = NULL; DBG("new_athread called\n"); if ((p = (athread *)calloc(sizeof(athread), 1)) == NULL) { a1loge(g_log, 1, "new_athread: calloc failed\n"); return NULL; } p->function = function; p->context = context; p->wait = athread_wait; p->del = athread_del; /* Create a thread */ #ifdef USE_BEGINTHREAD p->th = _beginthread(threadproc, 0, (void *)p); if (p->th == -1) { #else p->th = CreateThread(NULL, 0, threadproc, (void *)p, 0, NULL); if (p->th == NULL) { #endif a1loge(g_log, 1, "new_athread: CreateThread failed with %d\n",GetLastError()); p->th = NULL; athread_del(p); return NULL; } DBG("new_athread returning OK\n"); return p; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Delete a file */ void delete_file(char *fname) { _unlink(fname); } /* Given the path to a file, ensure that all the parent directories */ /* are created. return nz on error */ int create_parent_directories(char *path) { struct _stat sbuf; char *pp = path; if (*pp != '\000' /* Skip drive number */ && ((*pp >= 'a' && *pp <= 'z') || (*pp >= 'A' && *pp <= 'Z')) && pp[1] == ':') pp += 2; if (*pp == '/') pp++; /* Skip root directory */ for (;pp != NULL && *pp != '\000';) { if ((pp = strchr(pp, '/')) != NULL) { *pp = '\000'; if (_stat(path,&sbuf) != 0) { if (_mkdir(path) != 0) return 1; } *pp = '/'; pp++; } } return 0; } #endif /* NT */ /* ============================================================= */ /* UNIX/OS X */ /* ============================================================= */ #if defined(UNIX) /* Wait for and return the next character from the keyboard */ /* (If not_interactive, return getchar()) */ int next_con_char(void) { struct pollfd pa[1]; /* Poll array to monitor stdin */ struct termios origs, news; char rv = 0; if (!not_interactive) { /* Configure stdin to be ready with just one character */ if (tcgetattr(STDIN_FILENO, &origs) < 0) a1logw(g_log, "next_con_char: tcgetattr failed with '%s' on stdin", strerror(errno)); news = origs; news.c_lflag &= ~(ICANON | ECHO); news.c_cc[VTIME] = 0; news.c_cc[VMIN] = 1; if (tcsetattr(STDIN_FILENO,TCSANOW, &news) < 0) a1logw(g_log, "next_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); } /* Wait for stdin to have a character */ pa[0].fd = STDIN_FILENO; pa[0].events = POLLIN | POLLPRI; pa[0].revents = 0; if (poll_x(pa, 1, -1) > 0 && (pa[0].revents == POLLIN || pa[0].revents == POLLPRI)) { char tb[3]; if (read(STDIN_FILENO, tb, 1) > 0) { /* User hit a key */ rv = tb[0] ; } } else { if (!not_interactive) tcsetattr(STDIN_FILENO, TCSANOW, &origs); a1logw(g_log, "next_con_char: poll on stdin returned unexpected value 0x%x",pa[0].revents); } /* Restore stdin */ if (!not_interactive && tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0) { a1logw(g_log, "next_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); } return rv; } /* If here is one, return the next character from the keyboard, else return 0 */ /* (If not_interactive, always returns 0) */ int poll_con_char(void) { struct pollfd pa[1]; /* Poll array to monitor stdin */ struct termios origs, news; char rv = 0; if (!not_interactive) { /* Configure stdin to be ready with just one character */ if (tcgetattr(STDIN_FILENO, &origs) < 0) a1logw(g_log, "poll_con_char: tcgetattr failed with '%s' on stdin", strerror(errno)); news = origs; news.c_lflag &= ~(ICANON | ECHO); news.c_cc[VTIME] = 0; news.c_cc[VMIN] = 1; if (tcsetattr(STDIN_FILENO,TCSANOW, &news) < 0) a1logw(g_log, "poll_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); } /* Wait for stdin to have a character */ pa[0].fd = STDIN_FILENO; pa[0].events = POLLIN | POLLPRI; pa[0].revents = 0; if (poll_x(pa, 1, 0) > 0 && (pa[0].revents == POLLIN || pa[0].revents == POLLPRI)) { char tb[3]; if (read(STDIN_FILENO, tb, 1) > 0) { /* User hit a key */ rv = tb[0] ; } } /* Restore stdin */ if (!not_interactive && tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0) a1logw(g_log, "poll_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); return rv; } /* Suck all characters from the keyboard */ /* (If not_interactive, does nothing) */ void empty_con_chars(void) { if (not_interactive) return; tcflush(STDIN_FILENO, TCIFLUSH); } /* - - - - - - - - - - - - - - - - - - - - - - - - */ int acond_timedwait_imp(pthread_cond_t *cond, pthread_mutex_t *lock, int msec) { struct timeval tv; struct timespec ts; int rv; // this is unduly complicated... gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec + msec/1000; ts.tv_nsec = (tv.tv_usec + (msec % 1000) * 1000) * 1000L; if (ts.tv_nsec > 1000000000L) { ts.tv_nsec -= 1000000000L; ts.tv_sec++; } rv = pthread_cond_timedwait(cond, lock, &ts); return rv; } /* - - - - - - - - - - - - - - - - - - - - - - - - */ #ifdef NEVER /* Not currently needed, or effective */ /* Set the current threads priority */ int set_interactive_priority() { #ifdef UNIX_APPLE #ifdef NEVER int rv = 0; struct task_category_policy tcatpolicy; tcatpolicy.role = TASK_FOREGROUND_APPLICATION; if (task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY, (thread_policy_t)&tcatpolicy, TASK_CATEGORY_POLICY_COUNT) != KERN_SUCCESS) rv = 1; // a1logd(g_log, 8, "set_interactive_priority: set to forground got %d\n",rv); return rv; #else int rv = 0; struct thread_precedence_policy tppolicy; tppolicy.importance = 500; if (thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&tppolicy, THREAD_PRECEDENCE_POLICY_COUNT) != KERN_SUCCESS) rv = 1; // a1logd(g_log, 8, "set_interactive_priority: set to important got %d\n",rv); return rv; #endif /* NEVER */ #else /* !UNIX_APPLE */ int rv; struct sched_param param; param.sched_priority = 32; /* This doesn't work unless we're running as su :-( */ rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); // a1logd(g_log, 8, "set_interactive_priority: set got %d\n",rv); return rv; #endif /* !UNIX_APPLE */ } int set_normal_priority() { #ifdef UNIX_APPLE #ifdef NEVER int rv = 0; struct task_category_policy tcatpolicy; tcatpolicy.role = TASK_UNSPECIFIED; if (task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY, (thread_policy_t)&tcatpolicy, TASK_CATEGORY_POLICY_COUNT) != KERN_SUCCESS) rev = 1; // a1logd(g_log, 8, "set_normal_priority: set to normal got %d\n",rv); #else int rv = 0; struct thread_precedence_policy tppolicy; tppolicy.importance = 1; if (thread_policy_set(mach_thread_self(), THREAD_STANDARD_POLICY, (thread_policy_t)&tppolicy, THREAD_STANDARD_POLICY_COUNT) != KERN_SUCCESS) rv = 1; // a1logd(g_log, 8, "set_normal_priority: set to standard got %d\n",rv); return rv; #endif /* NEVER */ #else /* !UNIX_APPLE */ struct sched_param param; param.sched_priority = 0; int rv; rv = pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); // a1logd(g_log, 8, "set_normal_priority: reset got %d\n",rv); return rv; #endif /* !UNIX_APPLE */ } #endif /* NEVER */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static athread *beep_thread = NULL; static int beep_delay; static int beep_freq; static int beep_msec; /* Delayed beep handler */ static int delayed_beep(void *pp) { msec_sleep(beep_delay); a1logd(g_log,8, "msec_beep activate\n"); #ifdef UNIX_APPLE # if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 AudioServicesPlayAlertSound(kUserPreferredAlert); # else SysBeep((beep_msec * 60)/1000); # endif #else /* UNIX */ /* Linux is pretty lame in this regard... */ fprintf(stdout, "\a"); fflush(stdout); #endif return 0; } /* Activate the system beeper */ void msec_beep(int delay, int freq, int msec) { a1logd(g_log,8, "msec_beep %d msec\n",msec); if (delay > 0) { if (beep_thread != NULL) beep_thread->del(beep_thread); beep_delay = delay; beep_freq = freq; beep_msec = msec; if ((beep_thread = new_athread(delayed_beep, NULL)) == NULL) a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n"); } else { a1logd(g_log,8, "msec_beep activate\n"); #ifdef UNIX_APPLE # if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 AudioServicesPlayAlertSound(kUserPreferredAlert); # else SysBeep((msec * 60)/1000); # endif #else /* UNIX */ fprintf(stdout, "\a"); fflush(stdout); #endif } } #ifdef NEVER /* If we're UNIX and running on X11, we could do this */ /* sort of thing (from xset) to sound a beep, */ /* IF we were linking with X11: */ static void set_bell_vol(Display *dpy, int percent) { XKeyboardControl values; XKeyboardState kbstate; values.bell_percent = percent; if (percent == DEFAULT_ON) values.bell_percent = SERVER_DEFAULT; XChangeKeyboardControl(dpy, KBBellPercent, &values); if (percent == DEFAULT_ON) { XGetKeyboardControl(dpy, &kbstate); if (!kbstate.bell_percent) { values.bell_percent = -percent; XChangeKeyboardControl(dpy, KBBellPercent, &values); } } return; } static void set_bell_pitch(Display *dpy, int pitch) { XKeyboardControl values; values.bell_pitch = pitch; XChangeKeyboardControl(dpy, KBBellPitch, &values); return; } static void set_bell_dur(Display *dpy, int duration) { XKeyboardControl values; values.bell_duration = duration; XChangeKeyboardControl(dpy, KBBellDuration, &values); return; } XBell(..); #endif /* NEVER */ /* - - - - - - - - - - - - - - - - - - - - - - - - */ /* Wait for the thread to exit. Return the result */ static int athread_wait(struct _athread *p) { if (p->finished) return p->result; pthread_join(p->thid, NULL); return p->result; } /* Destroy the thread */ static void athread_del( athread *p ) { DBG("athread_del called\n"); if (p == NULL) return; if (!p->finished) { pthread_cancel(p->thid); } pthread_join(p->thid, NULL); free(p); } static void *threadproc( void *param ) { athread *p = (athread *)param; /* Register this thread with the Objective-C garbage collector */ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 objc_registerThreadWithCollector(); #endif p->result = p->function(p->context); p->finished = 1; return 0; } athread *new_athread( int (*function)(void *context), void *context ) { int rv; athread *p = NULL; DBG("new_athread called\n"); if ((p = (athread *)calloc(sizeof(athread), 1)) == NULL) { a1loge(g_log, 1, "new_athread: calloc failed\n"); return NULL; } p->function = function; p->context = context; p->wait = athread_wait; p->del = athread_del; /* Create a thread */ rv = pthread_create(&p->thid, NULL, threadproc, (void *)p); if (rv != 0) { a1loge(g_log, 1, "new_athread: pthread_create failed with %d\n",rv); athread_del(p); return NULL; } DBG("About to exit new_athread()\n"); return p; } /* - - - - - - - - - - - - - - - - - - - - - - - - */ /* Delete a file */ void delete_file(char *fname) { unlink(fname); } /* Given the path to a file, ensure that all the parent directories */ /* are created. return nz on error */ int create_parent_directories(char *path) { struct stat sbuf; char *pp = path; mode_t mode = 0700; /* Default directory mode */ if (*pp == '/') pp++; /* Skip root directory */ for (;pp != NULL && *pp != '\000';) { if ((pp = strchr(pp, '/')) != NULL) { *pp = '\000'; if (stat(path,&sbuf) != 0) { if (mkdir(path, mode) != 0) return 1; } else mode = sbuf.st_mode; *pp = '/'; pp++; } } return 0; } #endif /* defined(UNIX) */ /* - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(UNIX_APPLE) || defined(NT) /* Thread to monitor and kill the named processes */ static int th_kkill_nprocess(void *pp) { kkill_nproc_ctx *ctx = (kkill_nproc_ctx *)pp; /* set result to 0 if it ever suceeds or there was no such process */ ctx->th->result = -1; while(ctx->stop == 0) { if (kill_nprocess(ctx->pname, ctx->log) >= 0) ctx->th->result = 0; msec_sleep(20); /* Don't hog the CPU */ } ctx->done = 1; return 0; } static void kkill_nprocess_del(kkill_nproc_ctx *p) { int i; p->stop = 1; DBG("kkill_nprocess del called\n"); for (i = 0; p->done == 0 && i < 100; i++) { msec_sleep(50); } if (p->done == 0) { /* Hmm */ a1logw(p->log,"kkill_nprocess del failed to stop - killing thread\n"); p->th->del(p->th); } del_a1log(p->log); free(p); DBG("kkill_nprocess del done\n"); } /* Start a thread to constantly kill a process. */ /* Call ctx->del() when done */ kkill_nproc_ctx *kkill_nprocess(char **pname, a1log *log) { kkill_nproc_ctx *p; DBG("kkill_nprocess called\n"); if (log != NULL && log->debug >= 8) { int i; a1logv(log, 8, "kkill_nprocess called with"); for (i = 0; pname[i] != NULL; i++) a1logv(log, 8, " '%s'",pname[i]); a1logv(log, 8, "\n"); } if ((p = (kkill_nproc_ctx *)calloc(sizeof(kkill_nproc_ctx), 1)) == NULL) { a1loge(log, 1, "kkill_nprocess: calloc failed\n"); return NULL; } p->pname = pname; p->log = new_a1log_d(log); p->del = kkill_nprocess_del; if ((p->th = new_athread(th_kkill_nprocess, p)) == NULL) { del_a1log(p->log); free(p); return NULL; } return p; } #ifdef NT /* Kill a list of named process. */ /* Kill the first process found, then return */ /* return < 0 if this fails. */ /* return 0 if there is no such process */ /* return 1 if a process was killed */ int kill_nprocess(char **pname, a1log *log) { PROCESSENTRY32 entry; HANDLE snapshot; int j; /* Get a snapshot of the current processes */ if ((snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)) == NULL) { return -1; } while(Process32Next(snapshot,&entry) != FALSE) { HANDLE proc; if (strcmp(entry.szExeFile, "spotread.exe") == 0 && (proc = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID)) != NULL) { if (TerminateProcess(proc,0) == 0) { a1logv(log, 8, "kill_nprocess: Failed to kill '%s'\n",entry.szExeFile); } else { a1logv(log, 8, "kill_nprocess: Killed '%s'\n",entry.szExeFile); } CloseHandle(proc); } for (j = 0;; j++) { if (pname[j] == NULL) /* End of list */ break; a1logv(log, 8, "kill_nprocess: Checking process '%s' against list '%s'\n", entry.szExeFile,pname[j]); if (strcmp(entry.szExeFile,pname[j]) == 0) { a1logv(log, 1, "kill_nprocess: killing process '%s' pid %d\n", entry.szExeFile,entry.th32ProcessID); if ((proc = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID)) == NULL || TerminateProcess(proc,0) == 0) { a1logv(log, 1, "kill_nprocess: kill process '%s' failed with %d\n", pname[j],GetLastError()); CloseHandle(proc); CloseHandle(snapshot); return -1; } CloseHandle(proc); /* Stop on first one found ? */ CloseHandle(snapshot); return 1; } } } CloseHandle(snapshot); return 0; } #endif /* NT */ #if defined(UNIX_APPLE) /* Kill a list of named process. */ /* Kill the first process found, then return */ /* return < 0 if this fails. */ /* return 0 if there is no such process */ /* return 1 if a process was killed */ int kill_nprocess(char **pname, a1log *log) { struct kinfo_proc *procList = NULL; size_t procCount = 0; static int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; size_t length; int rv = 0; int i, j; procList = NULL; for (;;) { int err; /* Establish the amount of memory needed */ length = 0; if (sysctl(name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0) == -1) { DBGF((DBGA,"sysctl #1 failed with %d\n", errno)); return -1; } /* Add some more entries in case the number of processors changed */ length += 10 * sizeof(struct kinfo_proc); if ((procList = malloc(length)) == NULL) { DBGF((DBGA,"malloc failed for %d bytes\n", length)); return -1; } /* Call again with memory */ if ((err = sysctl(name, (sizeof(name) / sizeof(*name)) - 1, procList, &length, NULL, 0)) == -1) { DBGF((DBGA,"sysctl #1 failed with %d\n", errno)); free(procList); return -1; } if (err == 0) { break; } else if (err == ENOMEM) { free(procList); procList = NULL; } } procCount = length / sizeof(struct kinfo_proc); /* Locate the processes */ for (i = 0; i < procCount; i++) { for (j = 0;; j++) { if (pname[j] == NULL) /* End of list */ break; a1logv(log, 8, "kill_nprocess: Checking process '%s' against list '%s'\n", procList[i].kp_proc.p_comm,pname[j]); if (strncmp(procList[i].kp_proc.p_comm,pname[j],MAXCOMLEN) == 0) { a1logv(log, 1, "kill_nprocess: killing process '%s' pid %d\n", pname[j],procList[i].kp_proc.p_pid); if (kill(procList[i].kp_proc.p_pid, SIGTERM) != 0) { a1logv(log, 1, "kill_nprocess: kill process '%s' failed with %d\n", pname[j],errno); free(procList); return -1; } /* Stop on first one found ? */ free(procList); return 1; } } } free(procList); return rv; } #endif /* UNIX_APPLE */ #endif /* UNIX_APPLE || NT */