1 /************************************************/
4 /* Jean-Marc Pigeon <jmp@safe.ca> 2009 */
6 /************************************************/
7 /* This program is free software; you can */
8 /* redistribute it and/or modify it under the */
9 /* terms of the GNU General Public License as */
10 /* published by the Free Software Foundation */
11 /* version 2 of the License */
13 /* This program is distributed in the hope that */
14 /* it will be useful, but WITHOUT ANY WARRANTY; */
15 /* without even the implied warranty of */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU General Public License */
18 /* for more details. */
20 /* You should have received a copy of the GNU */
21 /* General Public License along with this */
22 /* program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin Street, */
24 /* Fifth Floor, Boston, MA 02110-1301, USA. */
25 /************************************************/
29 /************************************************/
30 #include <sys/mount.h>
31 #include <sys/syscall.h>
48 /*container filesystem */
49 #define ROOTFS "rootfs" /*container root*/
50 #define OLDROOT ".oldroot" /*for pivot_root*/
51 #define CLONPID "first.pid" /*cont process 1*/
52 #define MTAB "/etc/mtab" /*mtab file */
56 /************************************************/
58 /* Defining pivot_root system call */
60 /************************************************/
61 static int pivot_root(const char * new_root,const char * put_old)
64 #ifndef __NR_pivot_root
65 #pragma message ("the pivot_root syscall is not available within \"sys/syscall.h\"")
66 #pragma message ("-> The pivot_root system call will generate an alert")
67 (void) apl_alert(0,"%s need the pivot_root system call!!!.",appname);
71 return(syscall(__NR_pivot_root, new_root, put_old));
77 /************************************************/
79 /* Returning the container path. */
80 /* contpath array is dynamically assigned */
81 /* need to be freed when not need anymore. */
83 /************************************************/
84 static char *getcontpath(char *contname)
91 vzpath=apl_appdir(d_vzgot);
92 (void) asprintf(&contpath,"%s/%s",vzpath,contname);
99 /************************************************/
101 /* Check is the container is here with */
102 /* all needed parts. */
104 /************************************************/
105 int cnt_iscontgood(char *contname)
116 contpath=getcontpath(contname);
117 while (proceed==true) {
119 case 0 : /*is container existing?*/
120 if (contpath!=(char *)0) {/*always. */
123 (void) asprintf(&rootpath,"%s/%s",contpath,ROOTFS);
124 if (apl_isdir(rootpath)<0) {
125 (void) apl_alert(0,"%s, rootfs directory missing within container \"cont\" directory",
128 phase=999; /*trouble trouble */
130 (void) free(rootpath);
133 case 1 : /*check/make oldroot dir*/
134 if (contpath!=(char *)0) {/*always. */
137 (void) asprintf(&oldpath,"%s/%s",contpath,OLDROOT);
138 if (apl_isdir(oldpath)<0) {
139 if (mkdir(oldpath,0700)<0) {
140 (void) apl_alert(0,"%s, unable to make %s directory for container <%s> (error=%s)",
141 appname,OLDROOT,contname,strerror(errno));
143 phase=999; /*trouble trouble */
146 (void) free(oldpath);
149 default : /*SAFE Guard */
155 (void) free(contpath);
161 /************************************************/
163 /* procedure to set an initial mtab */
164 /* contents WITHIN the clone rootfs */
166 /************************************************/
167 static int setmtab(char *contname)
179 while (proceed==true) {
181 case 0 : /*removing mtab file */
182 if (unlink(MTAB)<0) {
184 case ENOENT :/* file not existing:-}*/
187 (void) apl_alert(0,"%s, Unable to remove %s from container <%s> rootfs (error=<%s>)",
188 appname,MTAB,contname,strerror(errno));
189 phase=999; /*trouble trouble */
194 case 1 : /*creating new MTAB file*/
195 if ((fichier=fopen(MTAB,"w"))==(FILE *)0) {
196 (void) apl_alert(0,"%s, Unable to create %s within container <%s> rootfs (error=<%s>)",
197 appname,MTAB,contname,strerror(errno));
198 phase=999; /*trouble trouble */
201 case 2 : /*inserting contents */
202 if (fprintf(fichier,"%s / roofs rw 0 0\n",appname)<0) {
203 (void) apl_alert(0,"%s, Unable to write %s file in container <%s> (error=<%s>)",
204 appname,MTAB,contname,strerror(errno));
205 phase=999; /*trouble trouble */
207 (void) fclose(fichier);
209 case 3 : /*everything fine */
212 default : /*SAFE Guard */
223 /************************************************/
225 /* procedure to pivot the container root */
228 /************************************************/
229 int cnt_pivot(int foreground,char *contname)
238 contpath=getcontpath(contname);
241 while (proceed==true) {
243 case 0 : /*binding container file*/
244 if (mount(contpath,contpath,0,MS_BIND,0)<0) {
245 (void) apl_alert(0,"%s, unable to bind container <%s> directory (error=%s)",
246 appname,contname,strerror(errno));
247 phase=999; /*trouble trouble */
250 case 1 : /*moving to rootfs */
251 (void) cnt_setstdio(foreground,contname,"container.log");
252 if (chdir(contpath)<0) {
253 (void) apl_alert(0,"%s, unable to reach container <%s> directory (error=%s)",
254 appname,contname,strerror(errno));
255 phase=999; /*trouble trouble */
258 case 2 : /*moving to rootfs */
259 if (pivot_root(".",OLDROOT)<0) {
260 (void) apl_alert(0,"%s, unable to pivot container <%s> root (error=%s)",
261 appname,contname,strerror(errno));
262 phase=999; /*trouble trouble */
265 case 3 : /*umounting previous fs */
266 if (umount2(OLDROOT,MNT_DETACH)<0) {
267 (void) apl_alert(0,"%s, unable to unmount container <%s> oldroot (error=%s)",
268 appname,contname,strerror(errno));
269 phase=999; /*trouble trouble */
272 case 4 : /* chrooting to rootfs */
273 if (chdir(ROOTFS)<0) {
274 (void) apl_alert(0,"%s, unable to reach container <%s> rootfs (error=%s)",
275 appname,contname,strerror(errno));
276 phase=999; /*trouble trouble */
279 case 5 : /* everything fine */
281 (void) apl_alert(0,"%s, unable to rootfs container <%s> (error=%s)",
282 appname,contname,strerror(errno));
283 phase=999; /*trouble trouble */
286 case 6 : /* everything fine */
287 (void) setmtab(contname); /*initiat mtab */
288 (void) fprintf(stdout,"%s container chroot done\n",apl_ascsystime(time((time_t *)0)));
289 (void) fflush(stdout);
292 default : /*SAFE Guard */
298 (void) free(contpath);
304 /************************************************/
306 /* procedure to set a file with the clone */
309 /************************************************/
310 int cnt_setclonepid(char *contname,pid_t cpid)
323 contpath=getcontpath(contname);
324 (void) asprintf(&filename,"%s/%s",contpath,CLONPID);
327 while (proceed==true) {
329 case 0 : /*opening the file */
330 if ((fichier=fopen(filename,"w"))==(FILE *)0) {
331 (void) apl_alert(0,"%s, Unable to open pidfile <%s> (error=<%s>)",
332 appname,filename,strerror(errno));
333 phase=999; /*trouble trouble */
336 case 1 : /*writing PID in it */
337 if (fprintf(fichier,"%05d\n",cpid)<0) {
338 (void) apl_alert(0,"%s, Unable to write pidfile in container <%s> (error=<%s>)",
339 appname,contname,strerror(errno));
340 phase=999; /*trouble trouble */
342 (void) fclose(fichier);
344 case 2 : /*everything fine */
347 default : /*SAFE Guard */
353 (void) free(filename);
354 (void) free(contpath);
360 /************************************************/
362 /* procedure to get the clone pid stored */
363 /* within the clonpid file */
365 /************************************************/
366 pid_t cnt_getclonepid(char *contname)
375 contpath=getcontpath(contname);
376 (void) asprintf(&filename,"%s/%s",contpath,CLONPID);
377 if ((fichier=fopen(filename,"r"))!=(FILE *)0) {
380 (void) fgets(strloc,sizeof(strloc)-1,fichier);
381 (void) sscanf(strloc,"%d",&clonepid);
382 (void) fclose(fichier);
384 (void) free(filename);
385 (void) free(contpath);
391 /************************************************/
393 /* procedure to remove the file with the */
396 /************************************************/
397 int cnt_rmclonepid(char *contname)
406 contpath=getcontpath(contname);
407 (void) asprintf(&filename,"%s/%s",contpath,CLONPID);
408 if (unlink(filename)<0) {
409 (void) apl_alert(0,"%s, Unable to remove pidfile in container <%s> (error=<%s>)",
410 appname,contname,strerror(errno));
413 (void) free(filename);
414 (void) free(contpath);
420 /************************************************/
422 /* procedure to initialize the HOST side */
424 /************************************************/
425 int cnt_initscript(char *scriptname,const char *fmt,...)
442 varlibpath=apl_appdir(d_varlib);
443 (void) vasprintf(&parmlst,fmt,args);
444 (void) asprintf(&cmd,"%s/shell/%s %s",varlibpath,scriptname,parmlst);
447 while (proceed==true) {
449 case 0 : /*opening pip channel */
450 if ((canal=popen(cmd,"r"))==(FILE *)0) {
451 (void) apl_alert(0,"%s, Unable to pipe cmd <%s> (error=<%s>)",
452 appname,cmd,strerror(errno));
454 phase=999; /*trouble trouble */
457 case 1 : /*do we have feed back */
458 if (canal!=(FILE *)0) { /*always */
461 while (fgets(buffer,BSIZE,canal)!=(char *)0) {
462 (void) apl_cleanstring(buffer);
463 if ((debug>0)&&(verbose==true))
464 (void) apl_alert(0,"%s, pipe say: <%s>",appname,buffer);
466 (void) fprintf(stdout,"%s\n",buffer);
467 (void) fflush(stdout);
472 case 2 : /*closing pip */
473 status=pclose(canal);/*get pipe status */
475 default : /*SAFE Guard */
482 (void) free(parmlst);
483 (void) free(varlibpath);
490 /************************************************/
492 /* procedure to extract the container */
493 /* architecture available in the 'arch' */
496 /************************************************/
497 char *cnt_getarch(char *contname)
500 static char *availarch[]={
501 "i386","i686","x86_64",(char *)0
515 contpath=getcontpath(contname);
516 (void) asprintf(&filename,"%s/%s",contpath,"arch");
519 while (proceed==true) {
521 case 0 : /*let open the file */
522 if ((fichier=fopen(filename,"r"))==(FILE *)0) {
523 (void) apl_alert(0,"%s Unable to open file <%s> (error=<%s>)",
524 appname,filename,strerror(errno));
525 phase=999; /*trouble trouble */
528 case 1 : /*reading first line */
529 if (apl_getstr(fichier,buffer,sizeof(buffer),'#')==(char *)0) {
530 (void) apl_alert(0,"%s Unable to read file <%s> (file empty?)",
532 phase=999; /*trouble trouble */
534 (void) fclose(fichier);
536 case 2 : /*scanning line */
537 (void) apl_cleanstring(buffer);
538 if (strlen(buffer)>0) { /*always? */
541 for (i=0;availarch[i]!=(char *)0;i++) {
542 if (strcmp(availarch[i],buffer)==0) {
543 arch=strdup(availarch[i]);
544 proceed=false; /*found arch */
550 case 3 : /*scanning line */
551 (void) apl_alert(0,"%s file <%s>, arch <%s> unknown, setting default",
552 appname,filename,buffer);
554 default : /*SAFE Guard */
560 (void) free(filename);
561 (void) free(contpath);
562 if (arch==(char *)0) {
563 arch=strdup(availarch[0]);
570 /************************************************/
572 /* procedure to extract the container */
573 /* distribution type available in the */
576 /************************************************/
577 char *cnt_getdist(char *contname)
591 contpath=getcontpath(contname);
592 (void) asprintf(&filename,"%s/%s",contpath,"dist");
595 while (proceed==true) {
597 case 0 : /*let open the file */
598 if ((fichier=fopen(filename,"r"))==(FILE *)0) {
599 (void) apl_alert(0,"%s Unable to open file <%s> (error=<%s>)",
600 appname,filename,strerror(errno));
601 phase=999; /*trouble trouble */
604 case 1 : /*reading first line */
605 if (apl_getstr(fichier,buffer,sizeof(buffer),'#')==(char *)0) {
606 (void) apl_alert(0,"%s Unable to read file <%s> (file empty?)",
608 phase=999; /*trouble trouble */
610 (void) fclose(fichier);
612 case 2 : /*scanning line */
613 (void) apl_cleanstring(buffer);
616 default : /*SAFE Guard */
622 (void) free(filename);
623 (void) free(contpath);
624 if (dist==(char *)0) {
625 dist=strdup("unknown");
632 /************************************************/
634 /* procedure to assign a new STDOUT/STDERR */
635 /* and close STDIN. Done ONLY if the */
636 /* process is in background mode. */
638 /************************************************/
639 void cnt_setstdio(int foreground,char *contname,char *outname)
642 #define OPIO "unicnt.c:cnt_setstdio,"
656 contpath=getcontpath(contname);
657 (void) asprintf(&filename,"%s/%s.stdout",contpath,outname);
658 while (proceed==true) {
660 case 0 : /*open the new stdout */
661 (void) unlink(filename);
662 if ((newstdout=open(filename,O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP))<0) {
663 (void) apl_alert(0,"%s, Unable to open <%s> (error=<%s>)",
664 OPIO,filename,strerror(errno));
665 phase=999; /*trouble trouble */
668 case 1 : /*open the new stderr */
669 (void) free(filename);
670 (void) asprintf(&filename,"%s/%s.stderr",contpath,outname);
671 (void) unlink(filename);
672 if ((newstderr=open(filename,O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP))<0) {
673 (void) apl_alert(0,"%s, Unable to open <%s> (error=<%s>)",
674 OPIO,filename,strerror(errno));
675 (void) close(newstdout);
676 phase=999; /*trouble trouble */
679 case 2 : /*duplicating stdout */
680 if (dup2(newstdout,1)<0) {
681 (void) apl_alert(0,"%s, Unable to dup2 stdout (error=<%s>)",
682 OPIO,strerror(errno));
683 (void) close(newstderr);
684 (void) close(newstdout);
688 case 3 : /*duplicating stderr */
689 (void) close(newstdout);
690 if (dup2(newstderr,2)<0) {
691 (void) apl_alert(0,"%s, Unable to dup2 stderr (error=<%s>)",
692 OPIO,strerror(errno));
693 (void) close(newstderr);
697 case 4 : /*setting new std */
698 if ((stdout=fdopen(1,"w"))==(FILE *)0) {
699 (void) apl_alert(0,"%s, Unable to fdopen stdout (error=<%s>)",
700 OPIO,strerror(errno));
702 if ((stderr=fdopen(2,"w"))==(FILE *)0) {
703 (void) apl_alert(0,"%s, Unable to fdopen stderr (error=<%s>)",
704 OPIO,strerror(errno));
706 (void) fclose(stdin);
708 case 5 : /*write time stamp */
709 (void) fprintf(stdout,"stdout start: %s\n",apl_ascsysdatetime(time((time_t *)0)));
710 (void) fprintf(stderr,"stderr start: %s\n",apl_ascsysdatetime(time((time_t *)0)));
711 (void) fflush(stdout);
712 (void) fflush(stderr);
714 default : /*SAFE Guard */
720 (void) free(filename);
721 (void) free(contpath);
727 /************************************************/
729 /* Procedure to wait for entry on the */
730 /* container console and forward it */
731 /* on the Master_container console file. */
732 /* A Management expiration is done */
733 /* according time. */
735 /************************************************/
736 int cnt_mstconsole(char *contname,pid_t cntpid)
739 #define OPCO "unicnt.c:cnt_console,"
741 #define RLX 5 /*number of sec */
746 struct timeval relax;
758 relax.tv_sec=RLX; /*sec relax time */
761 contpath=getcontpath(contname);
762 (void) asprintf(&filename,"%s/%s",contpath,"console");
765 while (proceed==true) {
767 case 0 : /*opening the M-Console*/
768 if ((mconsole=open(filename,O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR))<0) {
769 (void) apl_alert(0,"%s, Unable to open mconsole <%s> (error=<%s>)",
770 OPCO,filename,strerror(errno));
775 case 1 : /*opening the C-Console*/
776 (void) free(filename);
777 (void) asprintf(&filename,"%s/rootfs/dev/%s",contpath,"console");
778 if ((cconsole=open(filename,O_RDWR|O_ASYNC))<0) {
779 (void) apl_alert(0,"%s, Unable to open cconsole <%s> (error=<%s>)",
780 OPCO,filename,strerror(errno));
781 (void) close(mconsole);
786 case 2 : /*waiting event */
787 relax.tv_sec=RLX; /*sec relax time */
790 FD_SET(cconsole,&reading);
791 switch ((nbr=select(cconsole+1,&reading,(fd_set *)0,(fd_set *)0,&relax))) {
794 case EINTR: /*received a signal, lets see...*/
795 break; /*getting out fast */
797 (void) apl_alert(0,"%s, unexpected select event (error=<%s>)",
798 OPCO,strerror(errno));
802 case 0 : /*timeout child lost ? */
803 switch (waitpid(cntpid,0,WNOHANG)) {
804 case -1 : /*exiting */
805 (void) apl_alert(0,"Unexpect error on waitpid (error=<%s>)",strerror(errno));
808 case 0 : /*process still up! */
809 phase--; /*lets wait for console */
811 default : /*process exited! */
812 /*going to next phase */
816 default : /*data ready in cconsole*/
817 if ((nbr=read(cconsole,buffer,sizeof(buffer)))>0) {
818 (void) write(mconsole,buffer,nbr);
819 } /*forwarded to mconsole */
820 phase--; /*stay put on phase */
824 case 3 : /*closing console */
825 (void) close(mconsole);
826 (void) close(cconsole);
828 default : /*SAFE Guard */
834 (void) free(filename);
835 (void) free(contpath);