#include <syslog.h>
#include <pwd.h>
#include <grp.h>
-#include <ctype.h>
#include <limits.h>
+#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
-#include <sys/fcntl.h>
+#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
_exit(exitstatus);
}
-static void NONRETURNING sighandler_chld(int ignored) {
+static void reporttermination(int status) {
struct progress_msg progress_mbuf;
+
+ memset(&progress_mbuf,0,sizeof(progress_mbuf));
+ progress_mbuf.magic= PROGRESS_MAGIC;
+ progress_mbuf.type= pt_terminated;
+ progress_mbuf.data.terminated.status= status;
+ xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile);
+ xfflush(swfile);
+}
+
+static void NONRETURNING sighandler_chld(int ignored) {
int status;
pid_t returned;
if (returned!=child) syscallerror("spurious child process");
child= childtokill= -1;
- memset(&progress_mbuf,0,sizeof(progress_mbuf));
- progress_mbuf.magic= PROGRESS_MAGIC;
- progress_mbuf.type= pt_terminated;
- progress_mbuf.data.terminated.status= status;
- xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile);
- xfflush(swfile);
-
+ reporttermination(status);
syslog(LOG_INFO,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff);
_exit(0);
}
assert(fdarray[fd].iswrite == -1);
fdarray[fd].iswrite= (i>=request_mbuf.nreadfds);
}
+ /* fdarray[].iswrite now set; rest is still blank
+ * (ie want reject read, no realfd holdfd). */
assert(request_mbuf.nargs <= MAX_ARGSDEFVAR);
argarray= xmalloc(sizeof(char*)*(request_mbuf.nargs));
if (unlink(pipepathbuf)) syscallerror("unlink pipe");
if (close(tempfd)) syscallerror("close prelim fd onto pipe");
}
+ /* Now fdarray[].realfd is pipe end for service in case service
+ * wants it. If it's an input pipe, then .holdfd is the other
+ * (writing) end of the pipe - we keep it around so that the service
+ * doesn't get an apparently clean EOF if the caller disappears (eg
+ * due to a file read error) or the like (ie so that on disconnect
+ * we can guarantee to send the service SIGHUP before it gets EOF on
+ * the input fd). Otherwise, .holdfd=-1.
+ */
}
static void groupnames(int ngids, gid_t *gids, const char ***names_r) {
case tokv_word_requirefd:
if (fdarray[fd].realfd == -1)
failure("file descriptor %d required but not provided",fd);
- assert(fdarray[fd].holdfd == -1);
/* fall through */
case tokv_word_allowfd:
if (fdarray[fd].realfd == -1) {
}
}
}
+ /* Now fdarray[].realfd is exactly what service wants: pipe end or
+ * /dev/null or -1. If .realfd is not -1 then .holdfd may be the fd
+ * for the writing end of the corresponding pipe.
+ */
}
static void send_progress_ok(void) {
getevent(&event_mbuf);
assert(event_mbuf.type == et_confirm);
+ if (execbuiltin == bisexec_shutdown && !serviceuser_uid) {
+ /* The check for the uid is just so we can give a nice
+ * error message (in the actual code for bisexec_shutdown).
+ * If this is spoofed somehow then the unlink() will simply fail.
+ */
+ r= unlink(RENDEZVOUSPATH);
+ if (r) syscallfailure("remove rendezvous socket %s",RENDEZVOUSPATH);
+ syslog(LOG_NOTICE,"arranging for termination, due to client request");
+ reporttermination(0);
+ _exit(10);
+ }
+
fork_service_synch();
getevent(&event_mbuf);