1 #include "uogetopt.h"
2 #include "scheduled.h"
3 #include "open.h"
4 #include "attributes.h"
5 #include "stralloc.h"
6 #include "bailout.h"
7 #include "buffer.h"
8 #include "env.h"
9 #include "str.h"
10 #include "scan.h"
11 #include "error.h"
12 #include <unistd.h> /* read, write, fsync, chdir */
13 #include <sys/stat.h> /* fchmod */
14 
15 static const char *o_id;
16 static const char *o_dir;
17 static int o_dot_as_home;
18 static int o_env=0;
19 
20 static uogetopt2 myopts[]={
21 {'.',"dot-as-home",uogo_flag,UOGO_NOARG,&o_dot_as_home, 1 ,
22 "Use current directory instead of $HOME.",0,0},
23 {'d',"dir",uogo_string,0,&o_dir, 0 ,
24 "Jobdirectory.",
25 "Jobs will be read from this directory.","DIR"},
26 {'e',"copy-environment",uogo_flag,UOGO_NOARG,&o_env, 1 ,
27 "Clone current environment for job.",
28 "The default is to start new jobs in the daemons environment. This option "
29 "causes the current environment to be copied for the new process.",0},
30 {'i',"id",uogo_string,0,&o_id, 0 ,
31 "Unique ID for the new job.",
32 "An identifier must not be re-used and must not contain colons, slashes and "
33 "dots. If this option is not used then a unique ID will be given.", "ID"},
34 {0,0,0,0,0,0,0,0,0}
35 };
36 static void die_write(void) attribute_noreturn;
37 static void die_write_temp(void) attribute_noreturn;
38 static void die_fsync(void) attribute_noreturn;
39 static void die_fchmod(void) attribute_noreturn;
40 
die_write(void)41 static void die_write(void)  {xbailout(111,errno,"failed to write",0,0,0);}
die_write_temp(void)42 static void die_write_temp(void)
43 { xbailout(111,errno,"failed to write temporary file",0,0,0); }
die_fsync(void)44 static void die_fsync(void)
45 { xbailout(111,errno,"failed to fsync temporary file",0,0,0); }
die_fchmod(void)46 static void die_fchmod(void)
47 { xbailout(111,errno,"failed to fchmod temporary file",0,0,0); }
48 
49 extern char **environ;
50 #define W(b,s,l) do { \
51  if (-1==buffer_put(b,s,l)) die_write_temp(); \
52 } while (0)
53 
54 static void
copy_env(buffer * o)55 copy_env(buffer *o)
56 {
57 	unsigned int i;
58 	if (-1==buffer_puts(o,"env - \\\n")) die_write_temp();
59 	for (i=0;environ[i];i++) {
60 		char *e=environ[i];
61 		unsigned int j;
62 		j=str_chr(e,'=');
63 		if (!e[j])
64 			continue;
65 		W(o,e,j+1);
66 		W(o,"'",1);
67 		j++;
68 		while (e[j]) {
69 			if (e[j]=='\'')
70 				W(o,"'\\'",3);
71 			W(o,e+j,1);
72 			j++;
73 		}
74 		W(o,"' \\\n",4);
75 	}
76 }
77 
78 
79 static void
create_job(int fd,char ** args)80 create_job(int fd, char **args)
81 {
82 	buffer i;
83 	char ispace[512];
84 	buffer o;
85 	char ospace[512];
86 
87 	buffer_init(&o,(buffer_op) write,fd,ospace,sizeof(ospace));
88 	if (-1==buffer_puts(&o,"#! /bin/sh\n")) die_write_temp();
89 	if (o_env) {
90 		static stralloc fn;
91 		if (!stralloc_copys(&fn,o_id)) oom();
92 		if (!stralloc_cats(&fn,".run")) oom();
93 		if (!stralloc_0(&fn)) oom();
94 
95 		if (-1==buffer_puts(&o,"exec \\\n")) die_write_temp();
96 		copy_env(&o);
97 		if (-1==buffer_puts(&o,"/bin/sh -c ")) die_write_temp();
98 		if (-1==buffer_puts(&o,"\"$SCHEDULED_COMMAND_FILE\"/'"))
99 			die_write_temp();
100 		if (-1==buffer_puts(&o,fn.s)) die_write_temp();
101 		if (-1==buffer_puts(&o,"'\n")) die_write_temp();
102 		if (-1==buffer_flush(&o)) die_write_temp();
103 		if (-1==fchmod(fd,0755)) die_fchmod();
104 		if (-1==fsync(fd)) die_fsync();
105 		if (-1==close(fd)) die_write_temp();
106 		fd=open_excl(fn.s);
107 		if (fd==-1)
108 			xbailout(111,errno,"failed to open_excl ",fn.s,0,0);
109 		buffer_init(&o,(buffer_op) write,fd,ospace,sizeof(ospace));
110 		if (-1==buffer_puts(&o,"#! /bin/sh\n")) die_write_temp();
111 	}
112 
113 	if (args) {
114 		unsigned int j;
115 		const char *spc="";
116 		for (j=0;args[j];j++) {
117 			if (-1==buffer_puts(&o,spc)) die_write_temp();
118 			if (-1==buffer_puts(&o,args[j])) die_write_temp();
119 			spc=" ";
120 		}
121 	} else {
122 		buffer_init(&i,(buffer_op) read,0,ispace,sizeof(ispace));
123 		switch (buffer_copy(&o,&i)) {
124 		case 0: break;
125 		case -2: xbailout(111,errno,"failed to read input",0,0,0);
126 		case -3: die_write_temp();
127 		default: xbailout(100,errno,"unexpected errorcode from buffer_copy",0,0,0);
128 		}
129 	}
130 	if (-1==buffer_puts(&o,"\n")) die_write_temp();
131 	if (-1==buffer_flush(&o)) die_write_temp();
132 	if (-1==fchmod(fd,0755)) die_fchmod();
133 	if (-1==fsync(fd)) die_fsync();
134 	if (-1==close(fd)) die_write_temp();
135 }
136 static uogetopt_env myoptenv={
137 "uschedulecmd",PACKAGE,VERSION,
138 "uschedulecmd [options] [COMMAND ...]",
139 "This program creates a schedule command executing COMMAND or, if that is "
140 "not given, a command read from the standard input.",
141 "long",
142 "Report bugs to uschedule@lists.ohse.de",
143 0,0,0,0,uogetopt_out,myopts
144 };
145 
146 
main(int argc,char ** argv)147 int main(int argc, char **argv)
148 {
149 	int fd=-1; /* keep gcc quiet */
150 	int prt=0;
151 
152 	bailout_progname(argv[0]);
153 	flag_bailout_fatal_begin=3;
154 	uogo_posixmode=1;
155 	myoptenv.program=flag_bailout_log_name;
156 	uogetopt_parse(&myoptenv,&argc,argv);
157 
158 	change_dir(0,o_dir,o_dot_as_home);
159 	if (-1==chdir(IDDIR))
160 		xbailout(111,errno,"failed to chdir to ",IDDIR, " directory",0);
161 
162 	if (!o_id) {
163 		static stralloc sat;
164 		fd=make_id(&sat);
165 		o_id=sat.s;
166 		prt=1;
167 	} else {
168 		check_id(o_id);
169 		fd=open_excl(o_id);
170 		if (-1==fd)
171 			xbailout(111,errno,"failed to open_excl ",o_id,0,0);
172 	}
173 
174 	create_job(fd,argv[1] ? argv+1 : 0);
175 	if (prt) {
176 		if (-1==buffer_puts(buffer_1,"The id of the new job is ")) die_write();
177 		if (-1==buffer_puts(buffer_1,o_id)) die_write();
178 		if (-1==buffer_puts(buffer_1,"\n")) die_write();
179 		if (-1==buffer_flush(buffer_1)) die_write();
180 	}
181 	return 0;
182 }
183