wmwork: Add version 0.2.5 to repository.
[dockapps.git] / wmwork / src / wmwork.c
blob5d39e2136d3632ef156c49392278c45a2486885f
1 /* $Id: wmwork.c,v 1.67 2005/12/02 07:36:59 godisch Exp $
2 * vim: set noet ts=4:
4 * Copyright (c) 2002-2005 Martin A. Godisch <martin@godisch.de>
5 */
7 #include <assert.h>
8 #include <ctype.h>
9 #include <dirent.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <strings.h>
17 #include <unistd.h>
18 #include <time.h>
19 #include <sys/stat.h>
20 #include <sys/time.h>
21 #include <X11/xpm.h>
23 #ifdef SOLARIS
24 # include <strings.h>
25 # define PID_T "%lu"
26 #else /* SOLARIS */
27 # include <getopt.h>
28 # define PID_T "%u"
29 #endif /* SOLARIS */
31 #include "wmgeneral.h"
32 #include "wmwork.h"
33 #include "wmwork.xpm"
35 #define BUT_START (1)
36 #define BUT_PAUSE (2)
37 #define BUT_STOP (3)
38 #define BUT_PREV (4)
39 #define BUT_NEXT (5)
41 #define CHAR_SRC_X1(N) ((N - 'A') * 5)
42 #define CHAR_SRC_Y1 (71)
43 #define CHAR_SRC_X2(N) ((N - ' ') * 5)
44 #define CHAR_SRC_Y2 (64)
45 #define CHAR_SRC_X3(N) ((N - '{') * 5 + 65)
46 #define CHAR_SRC_Y3 (57)
47 #define TIMER_SRC_X(N) (N * 5 + 80)
48 #define TIMER_SRC_Y (64)
50 char
51 wmwork_mask_bits[64*64],
52 *dirName = NULL,
53 *logname = NULL,
54 *lockname = NULL;
55 struct timeval
56 now;
57 struct timezone
58 tz;
59 struct Project
60 *current = NULL,
61 *first = NULL;
62 time_t
63 sess_time = 0;
64 int
65 path_len = 0,
66 do_exit = 0;
68 static void handler(int signo)
70 do_exit = 1;
73 static void at_exit(void)
75 write_log();
76 write_record();
77 if (unlink(lockname) < 0) {
78 fprintf(stderr, "%s: cannot unlink '%s'\n", PACKAGE_NAME, lockname);
79 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
83 int main(int argc, char *argv[])
85 int n,
86 show_days = 0,
87 but_stat = 0,
88 microtm = 0,
89 running = 0,
90 force = 0;
91 time_t
92 last_time = 0;
93 char
94 *geometry = NULL,
95 *xdisplay = NULL;
96 static int signals[] =
97 {SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2, 0};
98 XEvent Event;
100 assert(sizeof(char) == 1);
102 umask(077);
103 do_opts(argc, argv, &show_days, &xdisplay, &geometry, &force);
105 path_len = strlen(getenv("HOME")) + strlen("/.wmwork/worklog") + 1;
106 if ((dirName = malloc(path_len)) == NULL || (logname = malloc(path_len)) == NULL || (lockname = malloc(path_len)) == NULL) {
107 fprintf(stderr, "%s: cannot allocate memory for path variable\n", PACKAGE_NAME);
108 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
109 exit(1);
111 snprintf(dirName, path_len, "%s/.wmwork", getenv("HOME"));
112 snprintf(logname, path_len, "%s/worklog", dirName);
113 snprintf(lockname, path_len, "%s/.#LOCK", dirName);
114 if (chdir(dirName) < 0) {
115 if (errno == ENOENT) {
116 if (mkdir(dirName, 0777)) {
117 fprintf(stderr, "%s: cannot mkdir '%s'\n", PACKAGE_NAME, dirName);
118 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
119 exit(1);
121 compat();
122 } else {
123 fprintf(stderr, "%s: cannot chdir into '%s'\n", PACKAGE_NAME, dirName);
124 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
125 exit(1);
129 for (n = 0; signals[n]; n++) {
130 if (signal(signals[n], handler) == SIG_ERR) {
131 fprintf(stderr, "%s: cannot set handler for signal %d\n", PACKAGE_NAME, signals[n]);
132 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
136 make_lock(force);
137 atexit(at_exit);
138 read_log();
139 current = first;
141 initXwindow(xdisplay);
142 createXBMfromXPM(wmwork_mask_bits, wmwork_master_xpm, 64, 64);
143 openXwindow(argc, argv, wmwork_master_xpm, wmwork_mask_bits, 64, 64, geometry, NULL);
144 AddMouseRegion(BUT_START, 5, 48, 22, 58);
145 AddMouseRegion(BUT_PAUSE, 23, 48, 40, 58);
146 AddMouseRegion(BUT_STOP, 41, 48, 58, 58);
147 AddMouseRegion(BUT_PREV, 5, 33, 16, 43);
148 AddMouseRegion(BUT_NEXT, 47, 33, 58, 43);
149 drawTime(current->time, sess_time, microtm, show_days, running);
150 drawProject(current->name);
152 while (1) {
153 last_time = now.tv_sec;
154 gettimeofday(&now, &tz);
155 if (running) {
156 current->time += now.tv_sec - last_time;
157 sess_time += now.tv_sec - last_time;
158 microtm = now.tv_usec;
159 drawTime(current->time, sess_time, microtm, show_days, running);
160 RedrawWindow();
162 while (XPending(display)) {
163 XNextEvent(display, &Event);
164 switch (Event.type) {
165 case Expose:
166 RedrawWindow();
167 break;
168 case DestroyNotify:
169 XCloseDisplay(display);
170 exit(0);
171 case ButtonPress:
172 n = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
173 switch (n) {
174 case BUT_START:
175 case BUT_PAUSE:
176 case BUT_STOP:
177 case BUT_PREV:
178 case BUT_NEXT:
179 ButtonDown(n);
180 break;
182 but_stat = n;
183 RedrawWindow();
184 break;
185 case ButtonRelease:
186 n = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
187 switch (but_stat) {
188 case BUT_START:
189 case BUT_PAUSE:
190 case BUT_STOP:
191 case BUT_PREV:
192 case BUT_NEXT:
193 ButtonUp(but_stat);
194 break;
196 if (but_stat && n == but_stat) {
197 switch (but_stat) {
198 case BUT_START:
199 running = 1;
200 break;
201 case BUT_PAUSE:
202 running = 0;
203 break;
204 case BUT_STOP:
205 write_log();
206 write_record();
207 running = 0;
208 sess_time = 0;
209 break;
210 case BUT_PREV:
211 if (!running && sess_time == 0)
212 current = current->prev;
213 break;
214 case BUT_NEXT:
215 if (!running && sess_time == 0)
216 current = current->next;
217 break;
219 drawTime(current->time, sess_time, microtm, show_days, running);
220 drawProject(current->name);
222 RedrawWindow();
223 but_stat = 0;
224 break;
227 usleep(50000L);
228 if (do_exit)
229 exit(0);
233 void ButtonDown(int button)
235 switch (button) {
236 case BUT_START:
237 copyXPMArea( 65, 25, 18, 11, 5, 48);
238 break;
239 case BUT_PAUSE:
240 copyXPMArea( 84, 25, 18, 11, 23, 48);
241 break;
242 case BUT_STOP:
243 copyXPMArea(103, 25, 18, 11, 41, 48);
244 break;
245 case BUT_PREV:
246 copyXPMArea(122, 25, 12, 11, 5, 33);
247 break;
248 case BUT_NEXT:
249 copyXPMArea(135, 25, 12, 11, 47, 33);
250 break;
254 void ButtonUp(int button)
256 switch (button) {
257 case BUT_START:
258 copyXPMArea( 65, 13, 18, 11, 5, 48);
259 break;
260 case BUT_PAUSE:
261 copyXPMArea( 84, 13, 18, 11, 23, 48);
262 break;
263 case BUT_STOP:
264 copyXPMArea(103, 13, 18, 11, 41, 48);
265 break;
266 case BUT_PREV:
267 copyXPMArea(122, 13, 12, 11, 5, 33);
268 break;
269 case BUT_NEXT:
270 copyXPMArea(135, 13, 12, 11, 47, 33);
271 break;
275 void ButtonEnable(int button)
277 return ButtonUp(button);
280 void ButtonDisable(int button)
282 switch (button) {
283 case BUT_START:
284 copyXPMArea( 65, 1, 18, 11, 5, 48);
285 break;
286 case BUT_PAUSE:
287 copyXPMArea( 84, 1, 18, 11, 23, 48);
288 break;
289 case BUT_STOP:
290 copyXPMArea(103, 1, 18, 11, 41, 48);
291 break;
292 case BUT_PREV:
293 copyXPMArea(122, 1, 12, 11, 5, 33);
294 break;
295 case BUT_NEXT:
296 copyXPMArea(135, 1, 12, 11, 47, 33);
297 break;
301 void do_opts(int argc, char *argv[], int *show_days, char **xdisplay, char **geometry, int *force)
303 static struct option long_opts[] = {
304 {"days", 0, NULL, 'd'},
305 {"force", 0, NULL, 'f'},
306 {"help", 0, NULL, 'h'},
307 {"version", 0, NULL, 'v'},
308 {"display", 1, NULL, 0 },
309 {"geometry", 1, NULL, 1 },
310 {NULL, 0, NULL, 0}};
311 int i, opt_index = 0;
313 #ifdef SOLARIS
314 for (i = 1; i < argc; i++) {
315 if (*argv[i] == '-') {
316 if (argv[i][1] == 'd')
317 *show_days = 1;
318 else if (argv[i][1] == 'f')
319 *force = 1;
320 else if (argv[i][1] == 'h') {
321 #else /* SOLARIS */
322 while (1) {
323 if ((i = getopt_long(argc, argv, "dfhv", long_opts, &opt_index)) == -1)
324 break;
325 switch (i) {
326 case 'd':
327 *show_days = 1;
328 break;
329 case 'f':
330 *force = 1;
331 break;
332 case 'h':
333 #endif /* SOLARIS */
334 printf("usage: %s [options]\n", argv[0]);
335 printf(" -d, --days display time in ddd.hh:mm instead of hhh:mm:ss,\n");
336 printf(" -f, --force overwrite stale lock files,\n");
337 printf(" -h, --help display this command line summary,\n");
338 printf(" -v, --version display the version number,\n");
339 printf(" --display=<id> open the mini window on display <id>, e.g. ':0.0',\n");
340 printf(" --geometry=<pos> open the mini window at position <pos>, e.g. '+10+10'.\n");
341 exit(0);
342 #ifdef SOLARIS
343 } else if (argv[i][1] == 'v') {
344 #else /* SOLARIS */
345 case 'v':
346 #endif /* SOLARIS */
347 printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
348 printf("copyright (c) 2002-2005 Martin A. Godisch <martin@godisch.de>\n");
349 exit(0);
350 #ifdef SOLARIS
351 } else if (!strcmp(argv[i], "--display"))
352 *xdisplay = optarg;
353 else if (!strcmp(argv[i], "--geometry"))
354 *geometry = optarg;
355 else break;
356 } else
357 break;
359 if (i < argc) {
360 fprintf(stderr, "%s: invalid argument -- %s\n", PACKAGE_NAME, argv[i]);
361 exit(1);
363 #else /* SOLARIS */
364 case 0:
365 *xdisplay = optarg;
366 break;
367 case 1:
368 *geometry = optarg;
369 break;
370 case '?':
371 exit(1);
374 if (optind < argc) {
375 fprintf(stderr, "%s: invalid argument -- %s\n", PACKAGE_NAME, argv[optind]);
376 exit(1);
378 #endif /* SOLARIS */
381 void drawTime(time_t time1, time_t time2, int microtm, int show_days, const int running)
383 time_t d1 = 0, d2 = 0, h1 = 0, h2 = 0;
384 short m1 = 0, m2 = 0, s1 = 0, s2 = 0;
386 if (time1 >= 3600000 || time2 >= 3600000)
387 show_days = 1;
389 if (show_days) {
390 d1 = time1 / 86400;
391 d2 = time2 / 86400;
392 time1 %= 86400;
393 time2 %= 86400;
394 if (d1 >= 1000 || d2 >= 1000) {
395 d1 %= 1000;
396 d2 %= 1000;
399 h1 = time1 / 3600;
400 h2 = time2 / 3600;
401 time1 %= 3600;
402 time2 %= 3600;
403 m1 = time1 / 60;
404 m2 = time2 / 60;
405 s1 = time1 % 60;
406 s2 = time2 % 60;
408 if (show_days) {
409 copyXPMArea(TIMER_SRC_X(d1 / 100), TIMER_SRC_Y, 5, 7, 7, 6);
410 d1 %= 100;
411 copyXPMArea(TIMER_SRC_X(d1 / 10), TIMER_SRC_Y, 5, 7, 13, 6);
412 copyXPMArea(TIMER_SRC_X(d1 % 10), TIMER_SRC_Y, 5, 7, 19, 6);
413 copyXPMArea(TIMER_SRC_X(h1 / 10), TIMER_SRC_Y, 5, 7, 29, 6);
414 copyXPMArea(TIMER_SRC_X(h1 % 10), TIMER_SRC_Y, 5, 7, 35, 6);
415 copyXPMArea(TIMER_SRC_X(m1 / 10), TIMER_SRC_Y, 5, 7, 45, 6);
416 copyXPMArea(TIMER_SRC_X(m1 % 10), TIMER_SRC_Y, 5, 7, 51, 6);
418 copyXPMArea(TIMER_SRC_X(d2 / 100), TIMER_SRC_Y, 5, 7, 7, 20);
419 d2 %= 100;
420 copyXPMArea(TIMER_SRC_X(d2 / 10), TIMER_SRC_Y, 5, 7, 13, 20);
421 copyXPMArea(TIMER_SRC_X(d2 % 10), TIMER_SRC_Y, 5, 7, 19, 20);
422 copyXPMArea(TIMER_SRC_X(h2 / 10), TIMER_SRC_Y, 5, 7, 29, 20);
423 copyXPMArea(TIMER_SRC_X(h2 % 10), TIMER_SRC_Y, 5, 7, 35, 20);
424 copyXPMArea(TIMER_SRC_X(m2 / 10), TIMER_SRC_Y, 5, 7, 45, 20);
425 copyXPMArea(TIMER_SRC_X(m2 % 10), TIMER_SRC_Y, 5, 7, 51, 20);
426 } else {
427 copyXPMArea(TIMER_SRC_X(h1 / 100), TIMER_SRC_Y, 5, 7, 7, 6);
428 h1 %= 100;
429 copyXPMArea(TIMER_SRC_X(h1 / 10), TIMER_SRC_Y, 5, 7, 13, 6);
430 copyXPMArea(TIMER_SRC_X(h1 % 10), TIMER_SRC_Y, 5, 7, 19, 6);
431 copyXPMArea(TIMER_SRC_X(m1 / 10), TIMER_SRC_Y, 5, 7, 29, 6);
432 copyXPMArea(TIMER_SRC_X(m1 % 10), TIMER_SRC_Y, 5, 7, 35, 6);
433 copyXPMArea(TIMER_SRC_X(s1 / 10), TIMER_SRC_Y, 5, 7, 45, 6);
434 copyXPMArea(TIMER_SRC_X(s1 % 10), TIMER_SRC_Y, 5, 7, 51, 6);
436 copyXPMArea(TIMER_SRC_X(h2 / 100), TIMER_SRC_Y, 5, 7, 7, 20);
437 h2 %= 100;
438 copyXPMArea(TIMER_SRC_X(h2 / 10), TIMER_SRC_Y, 5, 7, 13, 20);
439 copyXPMArea(TIMER_SRC_X(h2 % 10), TIMER_SRC_Y, 5, 7, 19, 20);
440 copyXPMArea(TIMER_SRC_X(m2 / 10), TIMER_SRC_Y, 5, 7, 29, 20);
441 copyXPMArea(TIMER_SRC_X(m2 % 10), TIMER_SRC_Y, 5, 7, 35, 20);
442 copyXPMArea(TIMER_SRC_X(s2 / 10), TIMER_SRC_Y, 5, 7, 45, 20);
443 copyXPMArea(TIMER_SRC_X(s2 % 10), TIMER_SRC_Y, 5, 7, 51, 20);
446 if (microtm < 500000 || !running) {
447 if (show_days) {
448 copyXPMArea(161, CHAR_SRC_Y1 + 4, 1, 3, 26, 10);
449 copyXPMArea(161, CHAR_SRC_Y1 + 4, 1, 3, 26, 24);
450 } else {
451 copyXPMArea(161, CHAR_SRC_Y1, 1, 7, 26, 6);
452 copyXPMArea(161, CHAR_SRC_Y1, 1, 7, 26, 20);
454 copyXPMArea(161, CHAR_SRC_Y1, 1, 7, 42, 6);
455 copyXPMArea(161, CHAR_SRC_Y1, 1, 7, 42, 20);
456 } else {
457 if (!show_days) {
458 copyXPMArea(163, CHAR_SRC_Y1, 1, 7, 26, 6);
459 copyXPMArea(163, CHAR_SRC_Y1, 1, 7, 26, 20);
461 copyXPMArea(163, CHAR_SRC_Y1, 1, 7, 42, 6);
462 copyXPMArea(163, CHAR_SRC_Y1, 1, 7, 42, 20);
466 void drawProject(const char *name)
468 int i;
470 for (i = 0; i < 3; i++) {
471 copyXPMArea(CHAR_SRC_X2(' '), CHAR_SRC_Y2, 5, 7, 23 + i * 6, 35);
472 if (i >= strlen(name))
473 continue;
474 if (name[i] >= 'A' && name[i] <= '`')
475 copyXPMArea(CHAR_SRC_X1(name[i]), CHAR_SRC_Y1, 5, 7, 23 + i * 6, 35);
476 else if (name[i] >= ' ' && name[i] <= '@')
477 copyXPMArea(CHAR_SRC_X2(name[i]), CHAR_SRC_Y2, 5, 7, 23 + i * 6, 35);
478 else if (name[i] >= '{' && name[i] <= '~')
479 copyXPMArea(CHAR_SRC_X3(name[i]), CHAR_SRC_Y3, 5, 7, 23 + i * 6, 35);
483 int read_log(void)
485 struct Project
486 *p = NULL;
487 FILE
488 *F = NULL;
489 char
490 buffer[512],
491 *colon = NULL,
492 *s = NULL;
493 int i, line, n = 0;
495 if ((first = malloc(sizeof(struct Project))) == NULL) {
496 fprintf(stderr, "%s: cannot allocate memory for element %d\n", PACKAGE_NAME, n);
497 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
498 exit(1);
500 strcpy(first->name, "---");
501 first->time = 0;
502 first->prev = first;
503 first->next = first;
505 if ((F = fopen(logname, "r")) == NULL) {
506 if (errno != ENOENT) {
507 fprintf(stderr, "%s: cannot open '%s' for reading\n", PACKAGE_NAME, logname);
508 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
510 return 1;
513 for (line = 1;; line++) {
514 fgets(buffer, sizeof(buffer), F);
515 if (feof(F))
516 break;
518 if (n == 0) {
519 p = first;
520 } else if ((p = malloc(sizeof(struct Project))) == NULL) {
521 fprintf(stderr, "%s: cannot allocate memory for element %d\n", PACKAGE_NAME, n);
522 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
523 return(n);
526 if ((s = index(buffer, '\n')) != NULL)
527 *s = '\0';
528 if (buffer[0] == '#' || buffer[0] == '\0') {
529 if (n)
530 free(p);
531 continue;
533 if ((colon = index(buffer, ':')) == NULL) {
534 fprintf(stderr, "%s: missing ':' in '%s' line %d\n", PACKAGE_NAME, logname, line);
535 if (n)
536 free(p);
537 continue;
539 i = colon - buffer < 3 ? colon - buffer : 3;
540 p->name[i] = '\0';
541 for (i--; i >= 0; i--) {
542 p->name[i] = toupper(buffer[i]);
543 if (p->name[i] == '/') {
544 fprintf(stderr, "%s: '/' is fs delimiter in '%s' line %d\n", PACKAGE_NAME, logname, line);
545 fprintf(stderr, "%s: converting forbidden '/' in project id into '|'\n", PACKAGE_NAME);
546 p->name[i] = '|';
549 p->time = strtol(++colon, &s, 10);
550 if (*s && *s != ':' && *s != ' ') {
551 fprintf(stderr, "%s: error converting timestamp '%s' in '%s' line %d\n", PACKAGE_NAME, colon, logname, line);
552 if (n)
553 free(p);
554 continue;
556 if (*s++ == ':') {
557 if ((p->comment = strdup(s)) == NULL) {
558 fprintf(stderr, "%s: ignored error while aquiring memory for comment string '%s' in '%s' line %d\n", PACKAGE_NAME, s, logname, line);
559 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
561 } else
562 p->comment = NULL;
564 p->prev = first->prev;
565 p->next = first;
566 p->prev->next = p;
567 p->next->prev = p;
568 n++;
571 fclose(F);
572 return(n);
575 int write_log(void)
577 struct Project
578 *p = NULL;
579 FILE
580 *F = NULL;
582 if ((F = fopen(logname, "w")) == NULL) {
583 fprintf(stderr, "%s: cannot open '%s' for writing\n", PACKAGE_NAME, logname);
584 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
585 F = stderr;
586 } else {
587 fprintf(F, "# wmwork configuration file\n");
588 fprintf(F, "# do not edit while wmwork is running\n\n");
590 p = first;
591 do {
592 if (F == stderr)
593 fprintf(F, "%s: > %s:%li:%s\n", PACKAGE_NAME, p->name, p->time, p->comment ? p->comment : "");
594 else
595 fprintf(F, "%s:%li:%s\n", p->name, p->time, p->comment ? p->comment : "");
596 p = p->next;
597 } while (p != first);
599 if (F == stderr)
600 return 0;
601 fclose(F);
602 return 1;
605 int write_record(void)
607 char
608 *fname = NULL,
609 tbuff[64],
610 rbuff[64];
611 FILE
612 *F = NULL;
614 if (sess_time == 0)
615 return 1;
616 strftime(tbuff, sizeof(tbuff), "%a, %d %b %Y %H:%M:%S %z", localtime(&now.tv_sec));
617 snprintf(rbuff, sizeof(rbuff), "%s %03li:%02li:%02li", tbuff, sess_time / 3600, sess_time / 60 % 60, sess_time % 60);
619 if ((fname = malloc(path_len)) == NULL) {
620 fprintf(stderr, "%s: cannot allocate memory for path variable\n", PACKAGE_NAME);
621 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
622 fprintf(stderr, "%s: > %s\n", PACKAGE_NAME, rbuff);
623 return 0;
625 snprintf(fname, path_len, "%s/.wmwork/%s", getenv("HOME"), current->name);
626 if ((F = fopen(fname, "a")) == NULL) {
627 fprintf(stderr, "%s: cannot open '%s' for writing\n", PACKAGE_NAME, fname);
628 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
629 fprintf(stderr, "%s: > %s\n", PACKAGE_NAME, rbuff);
630 free(fname);
631 return 0;
633 fprintf(F, "%s\n", rbuff);
634 fclose(F);
635 free(fname);
636 return 1;
639 int make_lock(int force)
641 FILE
642 *F = NULL;
643 pid_t
644 pid = 0;
646 fd = 0,
647 i = 0;
648 char
649 *c = NULL,
650 proc[32],
651 buffer[256];
653 if ((fd = open(lockname, O_WRONLY | O_CREAT | (force ? 0 : O_EXCL), 0666)) < 0) {
654 if (errno == EEXIST) {
655 if ((F = fopen(lockname, "r")) != NULL) {
656 i = fscanf(F, PID_T, &pid);
657 fclose(F);
658 snprintf(proc, sizeof(proc), "/proc/"PID_T"/exe", pid);
659 if (i == 1 && ((i = readlink(proc, buffer, sizeof(buffer)-1)) >= 0 || errno == ENOENT)) {
660 buffer[i] = 0;
661 if (i < 0 || ((c = rindex(buffer, '/')) != NULL && strcmp(c+1, "wmwork") != 0)) {
662 fprintf(stderr, "%s: found stale lock file (pid "PID_T")\n", PACKAGE_NAME, pid);
663 return make_lock(1);
667 fprintf(stderr, "%s: already running, --force will overwrite the lock file\n", PACKAGE_NAME);
668 exit(1);
670 fprintf(stderr, "%s: cannot create '%s'\n", PACKAGE_NAME, lockname);
671 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
672 return 0;
674 if ((F = fdopen(fd, "w")) != NULL) {
675 fprintf(F, PID_T"\n", getpid());
676 fclose(F);
677 } else
678 close(fd);
679 return 1;
682 int compat(void)
684 char
685 *temp1 = NULL,
686 *temp2 = NULL;
687 DIR *dir = NULL;
688 struct dirent
689 *entry = NULL;
691 /* BEGIN compatibility section for wmwork < 0.2.0 */
693 if ((temp1 = malloc(path_len)) == NULL || (temp2 = malloc(path_len)) == NULL) {
694 fprintf(stderr, "%s: cannot allocate memory for path variable\n", PACKAGE_NAME);
695 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
696 return -1;
699 snprintf(temp1, path_len, "%s/.wmworklog", getenv("HOME"));
700 if (rename(temp1, logname) < 0) {
701 if (errno == ENOENT)
702 return 0;
703 fprintf(stderr, "%s: cannot rename '%s' to '%s'\n", PACKAGE_NAME, temp1, logname);
704 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
705 return -1;
706 } else
707 fprintf(stderr, "%s: moving '%s' -> '%s'\n", PACKAGE_NAME, temp1, logname);
709 if ((dir = opendir(getenv("HOME"))) < 0) {
710 fprintf(stderr, "%s: cannot read '%s'\n", PACKAGE_NAME, getenv("HOME"));
711 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
712 return -1;
714 while ((entry = readdir(dir))) {
715 if (strstr(entry->d_name, ".wmwork.") == entry->d_name &&
716 strlen(entry->d_name) > 8 && strlen(entry->d_name) <= 11) {
717 snprintf(temp1, path_len, "%s/%s", getenv("HOME"), entry->d_name);
718 snprintf(temp2, path_len, "%s/%s", dirName, entry->d_name + 8);
719 if (rename(temp1, temp2) < 0) {
720 fprintf(stderr, "%s: cannot rename '%s' to '%s'\n", PACKAGE_NAME, temp1, temp2);
721 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, strerror(errno));
722 } else
723 fprintf(stderr, "%s: moving '%s' to '%s'\n", PACKAGE_NAME, temp1, temp2);
726 closedir(dir);
727 return 0;
729 /* END compatibility section for wmwork < 0.2.0 */