1 /*
2 * Changes for use with CM11A copyright 1996, 1997 Daniel B. Suthers,
3 * Pleasanton Ca, 94588 USA
4 * E-mail dbs@tanj.com
5 */
6 /*
7 * Copyright 1986 by Larry Campbell, 73 Concord Street, Maynard MA 01754 USA
8 * (maynard!campbell).
9 *
10 * John Chmielewski (tesla!jlc until 9/1/86, then rogue!jlc) assisted
11 * by doing the System V port and adding some nice features. Thanks!
12 *
13 */
14
15 /*
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 *
29 */
30
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD)
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41 #include <time.h>
42 #include <signal.h>
43 #include "x10.h"
44 #include "version.h"
45 #include <syslog.h>
46 #include "process.h"
47
48 #ifdef __GLIBC__
49 /* msf - added for glibc/rh 5.0 */
50 #include <sys/types.h>
51 #endif
52
53 extern int tty;
54 extern int sptty;
55 extern int usage();
56 extern int start_relay(),setup_sp_tty(), xread(), unit2int();
57 extern void error(), quit();
58 extern int lock_for_write();
59 extern int munlock();
60 extern CONFIG config; /* CWS - Structure with all configuration data */
61 extern CONFIG *configp;
62
63 int x10_housecode;
64 int verbose;
65 int i_am_relay = 0; /* flag to differentiate the relay process */
66 int port_locked = 0; /* flag to show that the tty port is locked */
67 int i_am_monitor = 0;
68 int i_am_state = 0;
69 int i_am_aux = 0;
70 int i_am_rfxmeter = 0;
71 int heyu_parent = D_CMDLINE;
72
73 FILE *fdsout;
74 FILE *fdserr;
75 FILE *fprfxo;
76 FILE *fprfxe;
77
78 void init();
79 int check4poll();
80
81 char heyuprogname[PATH_LEN + 1 + 10];
82
83 struct opt_st options;
84 struct opt_st *optptr = &options;
85
86 extern char *wday_name[7];
87 extern char *month_name[12];
88
89
90 /* Table for mapping units (1-16) or house codes (a-p) to 4 bit nibbles.
91 * element 0 equates to unit 1 or code a
92 */
93 unsigned char cm11map[]=
94 { 06, 016, 02, 012, 01, 011, 05, 015,
95 07, 017, 03, 013, 0, 010, 04, 014
96 };
97
98 /* Table for mapping an x10 format bitmap to a unit number. It's
99 * the reverse of the one above.
100 * Note that the unit numbers are 1-16, but the array is 0-15.
101 */
102 unsigned char map2cm11[]=
103 {
104 13, 5, 3, 11, 15, 7, 1, 9, 14, 6, 4, 12, 16, 8, 2, 10
105 };
106
107 int timeout = TIMEOUT;
108
109
110 extern int
111 c_date(), c_info(), c_monitor(), c_reset(), c_setclock(),
112 c_erase(), c_upload(), c_utility(), c_setclockraw(), c_command(),
113 is_heyu_cmd(), c_qerase(),
114 c_set_status(), c_show1(), c_show2(), c_x10state(), c_ping(), c_busywait(),
115 c_catchup(), c_macro(), c_start_engine(), c_logmsg(), c_readclock(),
116 c_flagstate(), c_cm10a_ident(), c_turn_rts_off(), c_turn_rts_on(),
117 c_trigger(), c_status_state(), c_powerfailtest(),
118 c_show_modem_lines(), c_ri_disable(), c_ri_enable(), c_port_line_test(),
119 c_start_aux(), c_start(), c_restart(), c_stop(), c_script_ctrl(),
120 c_arm(), c_sendarbst(), c_sensorfault(), c_armedstate(), c_settimer(),
121 c_sunstate(), c_restore_groups(), c_rfxcmds(), c_timer_times(), c_webhook(),
122 c_counter(), c_logtail(), c_modlist(), c_dmxcmds(), c_orecmds(), c_ore_emu(),
123 c_launch(), c_rts_pulser(), c_conflist(), c_sec_emu(), c_stateflaglist(),
124 c_masklist();
125
126 void init ( char * );
127 int read_config( unsigned char );
128
129 extern void create_alerts ( void );
130 extern int quick_ports_check ( void );
131
132 int c_list(), c_version();
133
134 struct cmdentry {
135 char *cmd_name;
136 int (*cmd_routine) ();
137 int lock_needed;
138 int internal_cmd;
139 } cmdtab[] = {
140 {"___", c_command,1,1},
141 {"date", c_date,1,0} ,
142 {"erase", c_erase,1,0},
143 {"info", c_info,1,1},
144 {"list", c_list,0,1},
145 {"monitor", c_monitor,0,1},
146 {"cmd", c_command,1,1},
147 {"reset", c_reset,1,0},
148 {"setclock", c_setclock,1,0},
149 {"readclock", c_readclock,1,0},
150 {"setclockraw", c_setclockraw, 1,0}, /* undocumented, see source - CWS */
151 {"upload", c_upload, 1, 0}, /* (added by CWS) */
152 {"utility", c_utility, 0, 1}, /* (added by CWS) */
153 {"newbattery", c_set_status, 1, 0},
154 {"purge", c_set_status, 1, 0},
155 {"clear", c_set_status, 1, 0},
156 {"reserved", c_set_status, 1, 0}, /* undocumented, see source - CWS */
157 {"version", c_version,0, 1},
158 {"qerase", c_qerase,1, 0}, /* hidden feature */
159 {"enginestate", c_x10state,1, 1},
160 {"initstate", c_x10state,1, 1},
161 {"initstateold", c_x10state, 1, 1},
162 {"initothers", c_x10state,1, 1},
163 {"fetchstate", c_x10state,1, 1},
164 {"onstate", c_x10state, 1, 1},
165 {"offstate", c_x10state, 1, 1},
166 {"dimstate", c_x10state, 1, 1},
167 {"fullonstate", c_x10state, 1, 1},
168 {"chgstate", c_x10state, 1, 1},
169 {"modchgstate", c_x10state, 1, 1},
170 {"alertstate", c_x10state, 1, 1},
171 {"clearstate", c_x10state, 1, 1},
172 {"auxalertstate", c_x10state, 1, 1},
173 {"auxclearstate", c_x10state, 1, 1},
174 {"addrstate", c_x10state, 1, 1},
175 {"lobatstate", c_x10state, 1, 1},
176 {"inactivestate", c_x10state, 1, 1},
177 {"activestate", c_x10state, 1, 1},
178 {"activechgstate", c_x10state, 1, 1},
179 {"validstate", c_x10state, 1, 1},
180 {"tamperstate", c_x10state, 1, 1},
181 {"dimlevel", c_x10state, 1, 1},
182 {"rawlevel", c_x10state, 1, 1},
183 {"memlevel", c_x10state, 1, 1},
184 {"rcstemp", c_x10state, 1, 1},
185 {"rawmemlevel", c_x10state, 1, 1},
186 {"vident", c_x10state, 1, 1},
187 {"sincelast", c_x10state, 1, 1},
188 {"statestr", c_x10state, 1, 1},
189 {"heyu_state", c_x10state, 1, 1},
190 {"heyu_vflagstate", c_x10state, 1, 1},
191 {"heyu_rawstate", c_x10state, 1, 1},
192 {"verbose_rawstate", c_x10state, 1, 1},
193 {"xtend_state", c_x10state, 1, 1},
194 {"catchup", c_catchup, 1, 0},
195 {"macro", c_macro, 1, 0},
196 {"trigger", c_trigger, 1, 0},
197 {"ping", c_ping, 1, 0},
198 {"show", c_show2, 1, 1},
199 {"engine", c_start_engine, 1, 1},
200 {"logmsg", c_logmsg, 1, 1},
201 {"wait", c_busywait, 1, 0},
202 {"flagstate", c_flagstate, 1, 1},
203 {"statusstate", c_status_state, 1, 1},
204 {"spendstate", c_status_state, 1, 1},
205 {"cm10a_init", c_cm10a_init, 1, 0},
206 {"cm10a_ident", c_cm10a_ident, 1, 0},
207 {"turn_rts_off", c_turn_rts_off, 1, 0},
208 {"turn_rts_on", c_turn_rts_on, 1, 0},
209 {"show_modem_lines", c_show_modem_lines, 1, 0},
210 {"powerfailtest", c_powerfailtest, 1, 1},
211 {"ri_disable", c_ri_disable, 1, 0},
212 {"ri_enable", c_ri_enable, 1, 0},
213 {"port_line_test", c_port_line_test, 1, 0},
214 {"rts_pulser", c_rts_pulser, 1, 1},
215 {"aux", c_start_aux, 1, 1},
216 {"start", c_start, 1, 1},
217 {"restart", c_restart, 1, 1},
218 {"stop", c_stop,0, 1},
219 {"script_ctrl", c_script_ctrl, 1, 1},
220 {"_arm", c_arm, 1, 1},
221 {"_disarm", c_arm, 1, 1},
222 {"sendarbst", c_sendarbst, 1, 0},
223 {"sensorfault", c_sensorfault, 1, 1},
224 {"armedstate", c_armedstate, 1, 1},
225 {"sunstate", c_sunstate, 1, 1},
226 {"nightstate", c_sunstate, 1, 1},
227 {"darkstate", c_sunstate, 1, 1},
228 {"restore_groups", c_restore_groups, 1, 0},
229 #ifdef HASRFXS
230 {"rfxflag_state", c_x10state, 1, 1},
231 {"rfxtemp", c_rfxcmds, 1, 1},
232 {"rfxrh", c_rfxcmds, 1, 1},
233 {"rfxbp", c_rfxcmds, 1, 1},
234 {"rfxvs", c_rfxcmds, 1, 1},
235 {"rfxvad", c_rfxcmds, 1, 1},
236 {"rfxvadi", c_rfxcmds, 1, 1},
237 {"rfxpot", c_rfxcmds, 1, 1},
238 {"rfxtemp2", c_rfxcmds, 1, 1},
239 {"rfxlobat", c_rfxcmds, 1, 1},
240 #endif
241 #ifdef HASRFXM
242 {"rfxflag_state", c_x10state, 1, 1},
243 {"rfxpower", c_rfxcmds, 1, 1},
244 {"rfxwater", c_rfxcmds, 1, 1},
245 {"rfxgas", c_rfxcmds, 1, 1},
246 {"rfxpulse", c_rfxcmds, 1, 1},
247 {"rfxcount", c_rfxcmds, 1, 1},
248 {"rfxpanel", c_rfxcmds, 1, 1},
249 #endif
250 #ifdef HASDMX
251 {"dmxflag_state", c_x10state, 1, 1},
252 {"dmxtemp", c_dmxcmds, 1, 1},
253 {"dmxsetpoint", c_dmxcmds, 1, 1},
254 {"dmxstatus", c_dmxcmds, 1, 1},
255 {"dmxmode", c_dmxcmds, 1, 1},
256 #endif /* HASDMX */
257 #ifdef HASORE
258 {"oreflag_state", c_x10state, 1, 1},
259 {"oretemp", c_orecmds, 1, 1},
260 {"orerh", c_orecmds, 1, 1},
261 {"orebp", c_orecmds, 1, 1},
262 {"orewgt", c_orecmds, 1, 1},
263 {"elscurr", c_orecmds, 1, 1},
264 {"orewindsp", c_orecmds, 1, 1},
265 {"orewindavsp", c_orecmds, 1, 1},
266 {"orewinddir", c_orecmds, 1, 1},
267 {"orerainrate", c_orecmds, 1, 1},
268 {"oreraintot", c_orecmds, 1, 1},
269 {"oreuv", c_orecmds, 1, 1},
270 {"owlpower", c_orecmds, 1, 1},
271 {"owlenergy", c_orecmds, 1, 1},
272 {"ore_emu", c_ore_emu, 1, 1},
273 #endif /* HASORE */
274 {"timer_times", c_timer_times, 1, 1},
275 {"webhook", c_webhook, 1, 1},
276 {"counter", c_counter, 1, 1},
277 {"logtail", c_logtail, 1, 1},
278 // {"modlist", c_modlist, 0, 1},
279 // {"conflist", c_conflist, 0, 1},
280 {"launch", c_launch, 1, 1},
281 {"sec_emu", c_sec_emu, 1, 1},
282 {"", NULL , 0, 0}
283 };
284
285 char *argptr;
286
287 /*-------------------------------------------------------------------+
288 | Main |
289 +-------------------------------------------------------------------*/
main(int argc,char * argv[])290 int main ( int argc, char *argv[] )
291 {
292 register int i;
293 int (*rtn) ();
294 struct cmdentry *c;
295 int retcode;
296 int ntokens;
297 char writefilename[PATH_LEN + 1];
298 char *cptr;
299 int start_engine_main();
300 int check_for_engine();
301 int check_dir_rw ( char *, char * );
302
303 configp = &config;
304
305 strncpy2(heyuprogname, argv[0], sizeof(heyuprogname) - 10);
306
307 /* Record if heyu was executed downstream of the heyu state engine or relay */
308 heyu_parent = D_CMDLINE;
309 if ( (cptr = getenv("HEYU_PARENT")) != NULL ) {
310 if ( strcmp(cptr, "RELAY") == 0 ) {
311 heyu_parent = D_RELAY;
312 i_am_state = 0;
313 }
314 else if ( strcmp(cptr, "ENGINE") == 0 ) {
315 heyu_parent = D_ENGINE;
316 i_am_state = 0;
317 }
318 else if ( strcmp(cptr, "AUXDEV") == 0 ) {
319 heyu_parent = D_AUXDEV;
320 i_am_state = 0;
321 }
322 }
323
324 fdsout = fprfxo = stdout;
325 fdserr = fprfxe = stderr;
326
327 rtn = NULL;
328
329
330 /* Check for and store options in options structure */
331 /* Return number of tokens used for options, or -1 */
332 /* if a usage error. */
333 ntokens = heyu_getopt(argc, argv, optptr);
334
335 if ( ntokens < 0 || (argc - ntokens) < 2 ) {
336 fprintf(stderr, "Heyu version %s\n", VERSION );
337 fprintf(stderr, "X10 Automation for Linux, Unix, and Mac OS X\n");
338 fprintf(stderr, "Copyright Charles W. Sullivan and Daniel B. Suthers\n");
339 fprintf(stderr,
340 "Usage: heyu [options] <command> (Enter 'heyu help' for commands.)\n");
341 return 1;
342 }
343
344 verbose = optptr->verbose;
345 if( verbose )
346 printf( "Version:%4s\n", VERSION );
347
348 /* Remove the tokens used for options from the argument list */
349 for ( i = 1; i < (argc - ntokens); i++ ) {
350 argv[i] = argv[i + ntokens];
351 }
352 argc -= ntokens;
353
354 if ( strcmp(argv[1], "list") == 0 ) {
355 c_list();
356 return 0;
357 }
358
359
360 if ( strcmp(argv[1], "help") == 0 ||
361 strcmp(argv[1], "syn") == 0 ||
362 strcmp(argv[1], "linewidth") == 0 ) {
363 c_command(argc, argv);
364 return 0;
365 }
366
367 if ( strcmp(argv[1], "utility") == 0 ) {
368 c_utility(argc, argv);
369 return 0;
370 }
371
372 if ( strcmp(argv[1], "modlist") == 0 ) {
373 return c_modlist(argc, argv);
374 }
375 else if ( strcmp(argv[1], "conflist") == 0 ) {
376 return c_conflist(argc, argv);
377 }
378 else if ( strcmp(argv[1], "stateflaglist") == 0 ) {
379 return c_stateflaglist(argc, argv);
380 }
381 else if ( strcmp(argv[1], "masklist") == 0 ) {
382 return c_masklist(argc, argv);
383 }
384
385 #if 0
386 if ( strcmp(argv[1], "webhook") == 0 ) {
387 c_webhook(argc, argv);
388 return 0;
389 }
390 #endif
391
392 if ( strcmp(argv[1], "show") == 0 ) {
393 retcode = c_show1(argc, argv);
394 if ( retcode == 0 ) {
395 free_all_arrays(configp);
396 return 0;
397 }
398 }
399
400 /* Commands other than those handled above require */
401 /* a configuration file and file locking. */
402
403 if ( strcmp(argv[1], "stop") == 0 )
404 read_minimal_config ( CONFIG_INIT, SRC_STOP );
405 else
406 read_config(CONFIG_INIT);
407
408 if ( is_heyu_cmd(argv[1]) ) {
409 /* This is a direct command */
410 c = cmdtab;
411 rtn = c->cmd_routine;
412 }
413 else {
414 /* This is an administrative or state command */
415 for (c = cmdtab + 1; c->cmd_routine != NULL; c++) {
416 if (strcmp(argv[1], c->cmd_name) == 0) {
417 if ( !(configp->device_type & DEV_DUMMY) || c->internal_cmd ) {
418 rtn = c->cmd_routine;
419 break;
420 }
421 else {
422 fprintf(stderr,
423 "Command '%s' is not valid for TTY dummy\n", c->cmd_name);
424 return 1;
425 }
426 }
427 }
428 }
429
430 if ( rtn == NULL ) {
431 fprintf(stderr,
432 "Usage: heyu [options] <command> (Enter 'heyu help' for commands.)\n");
433 return 1;
434 }
435
436
437 if ( (strcmp("stop", c->cmd_name) == 0 ) ||
438 (strcmp("version", c->cmd_name) == 0) ||
439 (strcmp("help", c->cmd_name) == 0) ) {
440 retcode = (*rtn)(); /* exits */
441 free_all_arrays(configp);
442 return retcode;
443 }
444
445 /* Check read/write permissions for spoolfile directory */
446 if ( check_dir_rw(SPOOLDIR, "SPOOL") != 0 ) {
447 fprintf(stderr, "%s\n", error_message());
448 return 1;
449 }
450
451 if ( quick_ports_check() != 0 ) {
452 fprintf(stderr, "Serial port %s is in use by another program.\n", configp->ttyaux);
453 return 1;
454 }
455
456 if ( c->lock_needed == 1 ) {
457 if ( lock_for_write() < 0 )
458 error("Program exiting.\n");
459 port_locked = 1;
460 }
461
462 argptr = argv[0];
463
464 /* Setup alert command arrays */
465 create_alerts();
466
467 /* Check for and start relay if not already running */
468 start_relay(configp->tty);
469 if ( ! i_am_relay ) {
470 setup_sp_tty();
471 }
472
473 if ( strcmp("start", c->cmd_name) == 0 &&
474 check_for_engine() != 0 &&
475 configp->start_engine == AUTOMATIC ) {
476 if ( heyu_parent == D_CMDLINE )
477 printf("starting heyu_engine\n");
478 init("engine");
479 c_start_engine(argc, argv);
480 }
481
482 if ( strcmp("start", c->cmd_name) == 0 &&
483 check_for_aux() != 0 &&
484 configp->ttyaux[0] != '\0' ) {
485 if ( heyu_parent == D_CMDLINE )
486 printf("starting heyu_aux\n");
487 init("aux");
488 c_start_aux(argc, argv);
489 }
490
491
492 #ifdef MINIEXCH
493 mxconnect(MINIXPORT);
494 #endif
495
496 init(c->cmd_name);
497
498 retcode = (*rtn) (argc, argv);
499 if ( port_locked == 1 ) {
500 sprintf(writefilename, "%s%s", WRITEFILE, configp->suffix);
501 munlock(writefilename);
502 }
503 free_all_arrays(configp);
504 return retcode;
505 }
506
507 /*-------------------------------------------------------------------+
508 | Init |
509 +-------------------------------------------------------------------*/
510
init(char * cmd_name)511 void init ( char *cmd_name )
512 {
513
514 timeout = TIMEOUT;
515 if( strcmp(cmd_name, "monitor") == 0 )
516 {
517 check4poll(1, 2);
518 }
519 else if ( strcmp(cmd_name, "engine") == 0 )
520 check4poll(0, 0);
521 else if ( strcmp(cmd_name, "info") == 0 )
522 check4poll(0, 0) ;
523 else
524 check4poll(0, 0);
525
526 /* Now check the status of the interface. */
527 /* if( get_status() < 1)
528 error("could not get the interface status");
529 */
530 }
531
532
533
534 /*
535 * Convert X10-style day of week (bit map, bit 0=monday, 6=sunday)
536 * to UNIX localtime(3) style day of week (integer, 0=sunday)
537 */
538 /* DBS NOTE: This is valid for CP290, not for CM11A.
539 * The CM11A uses unix style.
540 */
541
542
dowX2U(b)543 int dowX2U(b)
544 register char b;
545 {
546 register int n;
547
548 for (n = 1; (!(b & 1)) && n < 8; n++, b = b >> 1)
549 ;
550 if (n == 7)
551 n = 0;
552 if (n == 8)
553 n = 7;
554 return (n);
555 }
556
557
558
dowU2X(d)559 int dowU2X(d)
560 int d;
561 {
562 if (d == 0)
563 d = 7;
564 return (1 << (d - 1));
565 }
566
567
568
read_config(unsigned char mode)569 int read_config( unsigned char mode )
570 {
571 int retcode;
572
573 /* Read the user's Heyu configuration file and store in */
574 /* global CONFIG structure 'config'. Transfer some of */
575 /* the data into existing variables. */
576
577 retcode = get_configuration(mode);
578
579 x10_housecode = hc2code(configp->housecode);
580
581 return retcode;
582 }
583
584
585 /* Takes the bits in CM11A format (as used in the reply to a status)
586 * and returns a day string.
587 * The b parameter is for bitmap */
bits2day(b)588 char *bits2day(b)
589 int b;
590 {
591
592 switch(b)
593 {
594 case 1:
595 return("Sun");
596 case 2:
597 return("Mon");
598 case 4:
599 return("Tue");
600 case 8:
601 return("Wed");
602 case 16:
603 return("Thu");
604 case 32:
605 return("Fri");
606 case 64:
607 return("Sat");
608 }
609 return("Error");
610 }
611
c_version()612 int c_version()
613 {
614 printf( "Version:%4s\n", VERSION );
615 return(0);
616 }
617
display(RCCS)618 void display(RCCS)
619 char *RCCS;
620 {
621
622 /* This is not used much so far */
623 if( verbose > 1)
624 printf( "%s\n", RCCS);
625 }
626
627
628 /* List the variables as built into the program at compile time */
c_list()629 int c_list ()
630 {
631 if ( verbose ) {
632 printf( "Version: %s\n", VERSION );
633 printf( "The SPOOLDIR is %s\n", SPOOLDIR);
634 printf( "The LOCKDIR is %s\n", LOCKDIR);
635 printf( "The SYSBASEDIR is %s\n", SYSBASEDIR);
636 printf( "Number of Flags = %d\n", (32 * NUM_FLAG_BANKS));
637 printf( "Number of Counters = %d\n", (32 * NUM_COUNTER_BANKS));
638 printf( "Number of Timers = %d\n", (32 * NUM_TIMER_BANKS));
639 }
640 else {
641 printf( "Version=%s\n", VERSION );
642 printf( "SPOOLDIR=%s\n", SPOOLDIR);
643 printf( "LOCKDIR=%s\n", LOCKDIR);
644 printf( "SYSBASEDIR=%s\n", SYSBASEDIR);
645 printf( "Flags=%d\n", (32 * NUM_FLAG_BANKS));
646 printf( "Counters=%d\n", (32 * NUM_COUNTER_BANKS));
647 printf( "Timers=%d\n", (32 * NUM_TIMER_BANKS));
648 }
649
650 return 0;
651 }
652
653 /* Start command does nothing by itself */
654 /* but allows daemons to start. */
c_start(int argc,char * argv[])655 int c_start( int argc, char *argv[] )
656 {
657 return 0;
658 }
659
660 /* Reread configuration file */
reread_config(void)661 int reread_config ( void )
662 {
663 config.read_flag = 0;
664
665 /* Null out the option pointers so a restart will use */
666 /* the config file defined by env variable X10CONFIG */
667 if ( i_am_state || i_am_relay || i_am_aux || i_am_monitor ) {
668 optptr->configp = NULL;
669 optptr->subp = NULL;
670 }
671
672 return read_config(CONFIG_RESTART);
673
674 }
675
676 /* Check existance and read/write ability of a directory */
check_dir_rw(char * pathspec,char * label)677 int check_dir_rw ( char *pathspec, char *label )
678 {
679 struct stat statb;
680 gid_t grps[100];
681 int ngrps, j;
682 char errmsg[256];
683 int msgl = sizeof(errmsg) - 1;
684
685 clear_error_message();
686
687 if ( stat(pathspec, &statb) != 0 ) {
688 snprintf(errmsg, msgl, "%s directory %s does not exist", label, pathspec);
689 store_error_message(errmsg);
690 return 1;
691 }
692
693 #ifdef POSIX
694 if ( S_ISDIR(statb.st_mode) == 0 ) {
695 #else
696 if ( (statb.st_mode & S_IFDIR) != S_IFDIR ) {
697 #endif
698 snprintf(errmsg, msgl, "%s %s is not a directory", label, pathspec);
699 store_error_message(errmsg);
700 return 1;
701 }
702
703 if ( getuid() == 0 )
704 return 0;
705
706 if ( (statb.st_mode & S_IRWXU) == S_IRWXU &&
707 (statb.st_uid == getuid() || statb.st_uid == geteuid()) ) {
708 return 0;
709 }
710
711 if ( (statb.st_mode & S_IRWXG) == S_IRWXG ) {
712 if ( (ngrps = getgroups((sizeof(grps)/sizeof(gid_t)) - 1, grps)) < 0 ) {
713 snprintf(errmsg, msgl, "Internal error - getgroups()");
714 store_error_message(errmsg);
715 return 1;
716 }
717 grps[ngrps++] = getegid();
718 for ( j = 0; j < ngrps; j++ ) {
719 if ( statb.st_gid == grps[j] )
720 return 0;
721 }
722 }
723
724 if ( ((statb.st_mode & S_IRWXO) == S_IRWXO) )
725 return 0;
726
727 snprintf(errmsg, msgl, "Insufficient r/w permission for %s directory %s", label, pathspec);
728 store_error_message(errmsg);
729 return 1;
730 }
731
732