use setgroups() also
[util-vserver.git] / util-vserver / src / fakerunlevel.c
1 // $Id$
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on fakerunlevel.cc by Jacques Gelinas
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 //  
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //  
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 /*
21         This program add a RUNLEVEL record in a utmp file.
22         This is used when a vserver lack a private init process
23         so runlevel properly report the fake runlevel.
24 */
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include "util.h"
30
31 #include <utmp.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <grp.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40
41
42 static void
43 showHelp(int fd, int exit_code)
44 {
45   WRITE_MSG(fd,
46             "Usage: fakerunlevel <runlevel> <utmp_file>\n\n"
47             "Put a runlevel record in file <utmp_file>\n\n"
48             "Please report bugs to " PACKAGE_BUGREPORT "\n");
49
50   exit(exit_code);
51 }
52
53 static void
54 showVersion()
55 {
56   WRITE_MSG(1,
57             "fakerunlevel " VERSION "\n"
58             "This program is part of " PACKAGE_STRING "\n\n"
59             "Copyright (C) 2003 Enrico Scholz\n"
60             VERSION_COPYRIGHT_DISCLAIMER);
61   exit(0);
62 }
63
64 int main (int argc, char *argv[])
65 {
66   if (argc==1) showHelp(2,1);
67   if (strcmp(argv[1], "--help")==0)    showHelp(1,0);
68   if (strcmp(argv[1], "--version")==0) showVersion();
69   if (argc!=3) showHelp(2,1);
70
71   {
72     int  const          runlevel = atoi(argv[1]);
73     char const * const  fname    = argv[2];
74     int                 fd;
75     struct utmp         ut;
76     
77     gid_t               gid;
78     char                *gid_str = getenv("UTMP_GID");
79     
80     if (runlevel<0 || runlevel>6) showHelp(2,1);
81
82     if (chroot(".")==-1 ||
83         chdir("/")==-1) {
84       perror("chroot()/chdir()");
85       return EXIT_FAILURE;
86     }
87
88       // Real NSS is too expensive/insecure in this state; therefore, use the
89       // value detected at ./configure stage or overridden by $UTMP_GID
90       // env-variable
91     gid = gid_str ? atoi(gid_str) : UTMP_GID;
92     if (setgroups(1,&gid)==-1 ||
93         setgid(gid)==-1 ||
94         getgid()!=gid) {
95       perror("setgid()/getgid()");
96       return EXIT_FAILURE;
97     }
98
99     umask(002);
100     fd = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0664);
101     if (fd==-1) {
102       perror("open()");
103       return EXIT_FAILURE;
104     }
105
106     if (close(fd)==-1) {
107       perror("close()");
108       return EXIT_FAILURE;
109     }
110
111     utmpname (fname);
112     setutent();
113     memset (&ut,0,sizeof(ut));
114     ut.ut_type = RUN_LVL;
115     ut.ut_pid  = ('#' << 8) + runlevel+'0';
116     pututline (&ut);
117     endutent();
118   }
119
120   return EXIT_SUCCESS;
121 }