ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
main.c
Go to the documentation of this file.
1 #include "device.h"
2 #include "devnode.h"
3 #include "input.h"
4 #include "led.h"
5 #include "notify.h"
6 
7 static int main_ac;
8 static char **main_av;
9 
10 // usb.c
11 extern volatile int reset_stop;
12 extern int features_mask;
13 // device.c
14 extern int hwload_mode;
15 static void quitWithLock(char mut);
16 extern int restart();
17 
18 // Timespec utility function
19 void timespec_add(struct timespec* timespec, long nanoseconds){
20  nanoseconds += timespec->tv_nsec;
21  timespec->tv_sec += nanoseconds / 1000000000;
22  timespec->tv_nsec = nanoseconds % 1000000000;
23 }
24 
30 static void quit(){
31  quitWithLock(1);
32 }
33 
39 
40 void quitWithLock(char mut) {
41  // Abort any USB resets in progress
42  reset_stop = 1;
43  for(int i = 1; i < DEV_MAX; i++){
44  // Before closing, set all keyboards back to HID input mode so that the stock driver can still talk to them
45  if (mut) pthread_mutex_lock(devmutex + i);
46  if(IS_CONNECTED(keyboard + i)){
47  revertusb(keyboard + i);
48  closeusb(keyboard + i);
49  }
50  pthread_mutex_unlock(devmutex + i);
51  }
52  ckb_info("Closing root controller\n");
54  usbkill();
55 }
56 
57 void sighandler2(int type){
58  // Don't use ckb_warn, we want an extra \n at the beginning
59  printf("\n[W] Ignoring signal %d (already shutting down)\n", type);
60 }
61 
62 void sighandler(int type){
63  signal(SIGTERM, sighandler2);
64  signal(SIGINT, sighandler2);
65  signal(SIGQUIT, sighandler2);
66  printf("\n[I] Caught signal %d\n", type);
67  quit();
68  exit(0);
69 }
70 
71 void localecase(char* dst, size_t length, const char* src){
72  char* ldst = dst + length;
73  char s;
74  while((s = *src++)){
75  if(s == '_')
76  s = '-';
77  else
78  s = tolower(s);
79  *dst++ = s;
80  if(dst == ldst){
81  dst--;
82  break;
83  }
84  }
85  *dst = 0;
86 }
87 
88 int main(int argc, char** argv){
89  // Set output pipes to buffer on newlines, if they weren't set that way already
90  setlinebuf(stdout);
91  setlinebuf(stderr);
92  main_ac = argc;
93  main_av = argv;
94 
95  printf(" ckb: Corsair RGB driver %s\n", CKB_VERSION_STR);
96  // If --help occurs anywhere in the command-line, don't launch the program but instead print usage
97  for(int i = 1; i < argc; i++){
98  if(!strcmp(argv[i], "--help")){
99  printf(
100 #ifdef OS_MAC
101  "Usage: ckb-daemon [--gid=<gid>] [--hwload=<always|try|never>] [--nonotify] [--nobind] [--nomouseaccel] [--nonroot]\n"
102 #else
103  "Usage: ckb-daemon [--gid=<gid>] [--hwload=<always|try|never>] [--nonotify] [--nobind] [--nonroot]\n"
104 #endif
105  "\n"
106  "See https://github.com/ccMSC/ckb/blob/master/DAEMON.md for full instructions.\n"
107  "\n"
108  "Command-line parameters:\n"
109  " --gid=<gid>\n"
110  " Restrict access to %s* nodes to users in group <gid>.\n"
111  " (Ordinarily they are accessible to anyone)\n"
112  " --hwload=<always|try|never>\n"
113  " --hwload=always will force loading of stored hardware profiles on compatible devices. May result in long start up times.\n"
114  " --hwload=try will try to load the profiles, but give up if not immediately successful (default).\n"
115  " --hwload=never will ignore hardware profiles completely.\n"
116  " --nonotify\n"
117  " Disables key monitoring/notifications.\n"
118  " Note that this makes reactive lighting impossible.\n"
119  " --nobind\n"
120  " Disables all key rebinding, macros, and notifications. Implies --nonotify.\n"
121 #ifdef OS_MAC
122  " --nomouseaccel\n"
123  " Disables mouse acceleration, even if the system preferences enable it.\n"
124 #endif
125  " --nonroot\n"
126  " Allows running ckb-daemon as a non root user.\n"
127  " This will almost certainly not work. Use only if you know what you're doing.\n"
128  "\n", devpath);
129  exit(0);
130  }
131  }
132 
133  // Check PID, quit if already running
134  char pidpath[strlen(devpath) + 6];
135  snprintf(pidpath, sizeof(pidpath), "%s0/pid", devpath);
136  FILE* pidfile = fopen(pidpath, "r");
137  if(pidfile){
138  pid_t pid;
139  fscanf(pidfile, "%d", &pid);
140  fclose(pidfile);
141  if(pid > 0){
142  // kill -s 0 checks if the PID is active but doesn't send a signal
143  if(!kill(pid, 0)){
144  ckb_fatal_nofile("ckb-daemon is already running (PID %d). Try `killall ckb-daemon`.\n", pid);
145  ckb_fatal_nofile("(If you're certain the process is dead, delete %s and try again)\n", pidpath);
146  return 0;
147  }
148  }
149  }
150 
151  // Read parameters
152  int forceroot = 1;
153  for(int i = 1; i < argc; i++){
154  char* argument = argv[i];
155  unsigned newgid;
156  char hwload[7];
157  if(sscanf(argument, "--gid=%u", &newgid) == 1){
158  // Set dev node GID
159  gid = newgid;
160  ckb_info_nofile("Setting /dev node gid: %u\n", newgid);
161  } else if(!strcmp(argument, "--nobind")){
162  // Disable key notifications and rebinding
164  ckb_info_nofile("Key binding and key notifications are disabled\n");
165  } else if(!strcmp(argument, "--nonotify")){
166  // Disable key notifications
168  ckb_info_nofile("Key notifications are disabled\n");
169  } else if(sscanf(argument, "--hwload=%6s", hwload) == 1){
170  if(!strcmp(hwload, "always") || !strcmp(hwload, "yes") || !strcmp(hwload, "y") || !strcmp(hwload, "a")){
171  hwload_mode = 2;
172  ckb_info_nofile("Setting hardware load: always\n");
173  } else if(!strcmp(hwload, "tryonce") || !strcmp(hwload, "try") || !strcmp(hwload, "once") || !strcmp(hwload, "t") || !strcmp(hwload, "o")){
174  hwload_mode = 1;
175  ckb_info_nofile("Setting hardware load: tryonce\n");
176  } else if(!strcmp(hwload, "never") || !strcmp(hwload, "none") || !strcmp(hwload, "no") || !strcmp(hwload, "n")){
177  hwload_mode = 0;
178  ckb_info_nofile("Setting hardware load: never\n");
179  }
180  } else if(!strcmp(argument, "--nonroot")){
181  // Allow running as a non-root user
182  forceroot = 0;
183  }
184 #ifdef OS_MAC
185  else if(!strcmp(argument, "--nomouseaccel")){
186  // On OSX, provide an option to disable mouse acceleration
188  ckb_info_nofile("Mouse acceleration disabled\n");
189  }
190 #endif
191  }
192 
193  // Check UID
194  if(getuid() != 0){
195  if(forceroot){
196  ckb_fatal_nofile("ckb-daemon must be run as root. Try `sudo %s`\n", argv[0]);
197  exit(0);
198  } else
199  ckb_warn_nofile("Warning: not running as root, allowing anyway per command-line parameter...\n");
200  }
201 
202  // Make root keyboard
203  umask(0);
204  memset(keyboard, 0, sizeof(keyboard));
205  if(!mkdevpath(keyboard))
206  ckb_info("Root controller ready at %s0\n", devpath);
207 
208  // Set signals
209  sigset_t signals;
210  sigfillset(&signals);
211  sigdelset(&signals, SIGTERM);
212  sigdelset(&signals, SIGINT);
213  sigdelset(&signals, SIGQUIT);
214  sigdelset(&signals, SIGUSR1);
215  // Set up signal handlers for quitting the service.
216  sigprocmask(SIG_SETMASK, &signals, 0);
217  signal(SIGTERM, sighandler);
218  signal(SIGINT, sighandler);
219  signal(SIGQUIT, sighandler);
220  signal(SIGUSR1, (void (*)())restart);
221 
222  // Start the USB system
223  int result = usbmain();
224  quit();
225  return result;
226 }
227 
228 int restart() {
229  ckb_err("restart called, running quit without mutex-lock.\n");
230  quitWithLock(0);
231  return main(main_ac, main_av);
232 }
int features_mask
brief .
Definition: usb.c:35
static char ** main_av
Definition: main.c:8
int hwload_mode
hwload_mode = 1 means read hardware once. should be enough
Definition: device.c:7
#define FEAT_MOUSEACCEL
Definition: structures.h:148
int restart()
Definition: main.c:228
#define IS_CONNECTED(kb)
Definition: device.h:12
int usbmain()
Start the USB main loop. Returns program exit code when finished.
Definition: usb_linux.c:793
int mkdevpath(usbdevice *kb)
Create a dev path for the keyboard at index. Returns 0 on success.
Definition: devnode.c:268
#define ckb_err(fmt, args...)
Definition: includes.h:49
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
static void quit()
quit Stop working the daemon. function is called if the daemon received a sigterm In this case...
Definition: main.c:30
pthread_mutex_t devmutex[9]
Mutex for handling the usbdevice structure.
Definition: device.c:12
#define FEAT_BIND
Definition: structures.h:140
int main(int argc, char **argv)
Definition: main.c:88
void timespec_add(struct timespec *timespec, long nanoseconds)
Definition: main.c:19
QString devpath
Definition: kbmanager.cpp:4
long gid
Group ID for the control nodes. -1 to give read/write access to everybody.
Definition: devnode.c:16
#define ckb_warn_nofile(fmt, args...)
Definition: includes.h:50
#define ckb_fatal_nofile(fmt, args...)
Definition: includes.h:44
void ckb_info()
Definition: main.c:5
int closeusb(usbdevice *kb)
Definition: usb.c:687
void localecase(char *dst, size_t length, const char *src)
Definition: main.c:71
void sighandler2(int type)
Definition: main.c:57
volatile int reset_stop
brief .
Definition: usb.c:25
void sighandler(int type)
Definition: main.c:62
#define FEAT_NOTIFY
Definition: structures.h:141
#define DEV_MAX
Definition: device.h:8
void usbkill()
Stop the USB system.
Definition: usb_linux.c:853
static void quitWithLock(char mut)
quitWithLock
Definition: main.c:40
int rmdevpath(usbdevice *kb)
Remove the dev path for the keyboard at index. Returns 0 on success.
Definition: devnode.c:275
static int main_ac
Definition: main.c:7
#define ckb_info_nofile(fmt, args...)
Definition: includes.h:53
int revertusb(usbdevice *kb)
Definition: usb.c:417