Merge branch 'cupcake'
This commit is contained in:
commit
038862e152
|
@ -77,14 +77,6 @@ ifeq ($(HOST_OS),windows)
|
|||
$(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_OS),linux)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := \
|
||||
kdbg.c
|
||||
LOCAL_MODULE := kdbg
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
# adbd device daemon
|
||||
|
|
|
@ -91,7 +91,7 @@ host:<request>
|
|||
<host-prefix>:get-state
|
||||
Returns the state of a given device as a string.
|
||||
|
||||
<host-prefix>:forward:<local>:<remote>
|
||||
<host-prefix>:forward:<local>;<remote>
|
||||
Asks the ADB server to forward local connections from <local>
|
||||
to the <remote> address on a given device.
|
||||
|
||||
|
@ -135,15 +135,6 @@ shell:
|
|||
this to implement "adb shell", but will also cook the input before
|
||||
sending it to the device (see interactive_shell() in commandline.c)
|
||||
|
||||
bootdebug:
|
||||
Ask debugging information to the bootloader. The adbd daemon will
|
||||
respond with FAIL to this request.
|
||||
|
||||
bootloader:<command>
|
||||
Send a request to the bootloader. This can also work if the device
|
||||
is currently in the bootloader state. The adbd daemon will respond
|
||||
with FAIL to such requests.
|
||||
|
||||
remount:
|
||||
Ask adbd to remount the device's filesystem in read-write mode,
|
||||
instead of read-only. This is usually necessary before performing
|
||||
|
|
10
adb/adb.c
10
adb/adb.c
|
@ -985,16 +985,6 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
|
|||
return 0;
|
||||
}
|
||||
|
||||
if(!strncmp(service,"get-product",strlen("get-product"))) {
|
||||
char *out = "unknown";
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
||||
if (transport && transport->product) {
|
||||
out = transport->product;
|
||||
}
|
||||
snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
|
||||
char *out = "unknown";
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
||||
|
|
|
@ -144,7 +144,6 @@ void help()
|
|||
" adb start-server - ensure that there is a server running\n"
|
||||
" adb kill-server - kill the server if it is running\n"
|
||||
" adb get-state - prints: offline | bootloader | device\n"
|
||||
" adb get-product - prints: <product-id>\n"
|
||||
" adb get-serialno - prints: <serial-number>\n"
|
||||
" adb status-window - continuously print device status for a specified device\n"
|
||||
" adb remount - remounts the /system partition on the device read-write\n"
|
||||
|
@ -377,82 +376,6 @@ int interactive_shell(void)
|
|||
}
|
||||
|
||||
|
||||
|
||||
int adb_download_buffer(const char *service, const void* data, int sz,
|
||||
unsigned progress)
|
||||
{
|
||||
char buf[4096];
|
||||
unsigned total;
|
||||
int fd;
|
||||
const unsigned char *ptr;
|
||||
|
||||
snprintf(buf, sizeof buf, "%s:%d", service, sz);
|
||||
fd = adb_connect(buf);
|
||||
if(fd < 0) {
|
||||
fprintf(stderr,"error: %s\n", adb_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
adb_socket_setbufsize(fd, CHUNK_SIZE);
|
||||
|
||||
total = sz;
|
||||
ptr = data;
|
||||
|
||||
if(progress) {
|
||||
char *x = strrchr(service, ':');
|
||||
if(x) service = x + 1;
|
||||
}
|
||||
|
||||
while(sz > 0) {
|
||||
unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
|
||||
if(writex(fd, ptr, xfer)) {
|
||||
adb_status(fd);
|
||||
fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
|
||||
return -1;
|
||||
}
|
||||
sz -= xfer;
|
||||
ptr += xfer;
|
||||
if(progress) {
|
||||
int percent = 100 - (int)(100.0 * ((float)sz / (float)total));
|
||||
printf("sending: '%s' %4d%% \r", service, percent);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
if(progress) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(readx(fd, buf, 4)){
|
||||
fprintf(stderr,"* error reading response *\n");
|
||||
adb_close(fd);
|
||||
return -1;
|
||||
}
|
||||
if(memcmp(buf, "OKAY", 4)) {
|
||||
buf[4] = 0;
|
||||
fprintf(stderr,"* error response '%s' *\n", buf);
|
||||
adb_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
adb_close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int adb_download(const char *service, const char *fn, unsigned progress)
|
||||
{
|
||||
void *data;
|
||||
unsigned sz;
|
||||
|
||||
data = load_file(fn, &sz);
|
||||
if(data == 0) {
|
||||
fprintf(stderr,"* cannot read '%s' *\n", service);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return adb_download_buffer(service, data, sz, progress);
|
||||
}
|
||||
|
||||
static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
|
||||
{
|
||||
if (serial) {
|
||||
|
@ -678,13 +601,6 @@ static int logcat(transport_type transport, char* serial, int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int adb_download_data(const char *what, const void* data, int sz, unsigned progress)
|
||||
{
|
||||
char service[4096];
|
||||
snprintf(service, sizeof service, "bootloader:flash:%s", what);
|
||||
return adb_download_buffer(service, data, sz, 1);
|
||||
}
|
||||
|
||||
#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
|
||||
static int top_works(const char *top)
|
||||
{
|
||||
|
@ -977,32 +893,6 @@ top:
|
|||
}
|
||||
}
|
||||
|
||||
if(!strcmp(argv[0], "debug")) {
|
||||
int fd = adb_connect("bootdebug:");
|
||||
if(fd >= 0) {
|
||||
read_and_dump(fd);
|
||||
adb_close(fd);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr,"error: %s\n", adb_error());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(argv[0], "bl")) {
|
||||
int fd;
|
||||
if(argc != 2) return usage();
|
||||
snprintf(buf, sizeof buf, "bootloader:%s", argv[1]);
|
||||
fd = adb_connect(buf);
|
||||
if(fd >= 0) {
|
||||
read_and_dump(fd);
|
||||
adb_close(fd);
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr,"* command failed: %s *\n", adb_error());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(argv[0], "kill-server")) {
|
||||
int fd;
|
||||
fd = _adb_connect("host:kill");
|
||||
|
@ -1024,27 +914,6 @@ top:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* adb_download() commands */
|
||||
|
||||
if(!strcmp(argv[0], "send")) {
|
||||
if(argc != 3) return usage();
|
||||
snprintf(buf, sizeof buf, "bootloader:send:%s", argv[1]);
|
||||
if(adb_download(buf, argv[2], 1)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!strcmp(argv[0], "recover")) {
|
||||
if(argc != 2) return usage();
|
||||
if(adb_download("recover", argv[1], 1)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!strcmp(argv[0], "bugreport")) {
|
||||
if (argc != 1) {
|
||||
return 1;
|
||||
|
@ -1057,9 +926,7 @@ top:
|
|||
|
||||
if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
|
||||
char* service = argv[0];
|
||||
if (!strncmp(service, "wait-for-bootloader", strlen("wait-for-bootloader"))) {
|
||||
fprintf(stderr,"WAIT FOR BOOTLOADER\n");
|
||||
} else if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
|
||||
if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
|
||||
if (ttype == kTransportUsb) {
|
||||
service = "wait-for-usb";
|
||||
} else if (ttype == kTransportLocal) {
|
||||
|
@ -1157,7 +1024,6 @@ top:
|
|||
/* passthrough commands */
|
||||
|
||||
if(!strcmp(argv[0],"get-state") ||
|
||||
!strcmp(argv[0],"get-product") ||
|
||||
!strcmp(argv[0],"get-serialno"))
|
||||
{
|
||||
char *tmp;
|
||||
|
|
474
adb/kdbg.c
474
adb/kdbg.c
|
@ -1,474 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
|
||||
#include <linux/usb/ch9.h>
|
||||
#else
|
||||
#include <linux/usb_ch9.h>
|
||||
#endif
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <cutils/fdevent.h>
|
||||
#include "adb.h"
|
||||
|
||||
|
||||
#define TRACE_USB 0
|
||||
|
||||
#if TRACE_USB
|
||||
#define DBG1(x...) fprintf(stderr, x)
|
||||
#define DBG(x...) fprintf(stderr, x)
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#define DBG1(x...)
|
||||
#endif
|
||||
|
||||
struct usb_handle
|
||||
{
|
||||
struct usb_handle *next;
|
||||
char fname[32];
|
||||
int desc;
|
||||
unsigned char ep_in;
|
||||
unsigned char ep_out;
|
||||
unsigned int interface;
|
||||
};
|
||||
|
||||
static struct usb_handle *g_first_usb_device;
|
||||
static struct usb_handle *g_last_usb_device;
|
||||
|
||||
static void new_device(char *dev_name, unsigned char ep_in, unsigned char ep_out, unsigned int interface)
|
||||
{
|
||||
struct usb_handle* usb;
|
||||
|
||||
DBG("New device being added %s \n", dev_name);
|
||||
|
||||
usb = (struct usb_handle *)calloc(1, sizeof(struct usb_handle));
|
||||
strcpy(usb->fname, dev_name);
|
||||
usb->ep_in = ep_in;
|
||||
usb->ep_out = ep_out;
|
||||
usb->interface = interface;
|
||||
usb->next = NULL;
|
||||
if(g_last_usb_device)
|
||||
g_last_usb_device->next = usb;
|
||||
else
|
||||
g_first_usb_device = usb;
|
||||
g_last_usb_device = usb;
|
||||
}
|
||||
|
||||
|
||||
static inline int badname(const char *name)
|
||||
{
|
||||
if(!isdigit(name[0])) return 1;
|
||||
if(!isdigit(name[1])) return 1;
|
||||
if(!isdigit(name[2])) return 1;
|
||||
if(name[3] != 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_usb_devices(const char *base, unsigned vendor, unsigned product1, unsigned product2,
|
||||
unsigned ifclass, unsigned ifsubclass,
|
||||
unsigned ifprotocol, unsigned numendpoints)
|
||||
{
|
||||
char busname[32], devname[32];
|
||||
unsigned char local_ep_in, local_ep_out;
|
||||
DIR *busdir , *devdir ;
|
||||
struct dirent *de;
|
||||
int fd ;
|
||||
int ret_val = -1;
|
||||
int found_device = 0;
|
||||
|
||||
busdir = opendir(base);
|
||||
if(busdir == 0) return 0;
|
||||
|
||||
while((de = readdir(busdir)) != 0) {
|
||||
if(badname(de->d_name)) continue;
|
||||
|
||||
snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
|
||||
devdir = opendir(busname);
|
||||
if(devdir == 0) continue;
|
||||
|
||||
DBG("[ scanning %s ]\n", busname);
|
||||
while((de = readdir(devdir))) {
|
||||
if(badname(de->d_name)) continue;
|
||||
snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
|
||||
|
||||
DBG("[ scanning %s ]\n", devname);
|
||||
fd = open(devname, O_RDWR);
|
||||
if(fd < 0) {
|
||||
continue;
|
||||
} else {
|
||||
unsigned char devdesc[256];
|
||||
unsigned char* bufptr = devdesc;
|
||||
struct usb_device_descriptor* device;
|
||||
struct usb_config_descriptor* config;
|
||||
struct usb_interface_descriptor* interface;
|
||||
struct usb_endpoint_descriptor *ep1, *ep2;
|
||||
unsigned vid, pid;
|
||||
int i, interfaces;
|
||||
|
||||
size_t desclength = read(fd, devdesc, sizeof(devdesc));
|
||||
|
||||
// should have device and configuration descriptors, and atleast two endpoints
|
||||
if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
|
||||
DBG("desclength %d is too small\n", desclength);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
device = (struct usb_device_descriptor*)bufptr;
|
||||
bufptr += USB_DT_DEVICE_SIZE;
|
||||
if(device->bLength == USB_DT_DEVICE_SIZE && device->bDescriptorType == USB_DT_DEVICE) {
|
||||
vid = __le16_to_cpu(device->idVendor);
|
||||
pid = __le16_to_cpu(device->idProduct);
|
||||
pid = devdesc[10] | (devdesc[11] << 8);
|
||||
DBG("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
|
||||
if((vendor == vid) && (product1 == pid || product2 == pid)){
|
||||
|
||||
// should have config descriptor next
|
||||
config = (struct usb_config_descriptor *)bufptr;
|
||||
bufptr += USB_DT_CONFIG_SIZE;
|
||||
if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
|
||||
DBG("usb_config_descriptor not found\n");
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// loop through all the interfaces and look for the ADB interface
|
||||
interfaces = config->bNumInterfaces;
|
||||
for (i = 0; i < interfaces; i++) {
|
||||
if (bufptr + USB_DT_ENDPOINT_SIZE > devdesc + desclength)
|
||||
break;
|
||||
|
||||
interface = (struct usb_interface_descriptor *)bufptr;
|
||||
bufptr += USB_DT_INTERFACE_SIZE;
|
||||
if (interface->bLength != USB_DT_INTERFACE_SIZE ||
|
||||
interface->bDescriptorType != USB_DT_INTERFACE) {
|
||||
DBG("usb_interface_descriptor not found\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DBG("bInterfaceClass: %d, bInterfaceSubClass: %d,\
|
||||
bInterfaceProtocol: %d, bNumEndpoints: %d\n",
|
||||
interface->bInterfaceClass, interface->bInterfaceSubClass,
|
||||
interface->bInterfaceProtocol, interface->bNumEndpoints);
|
||||
// Sooner bootloader has zero for bInterfaceClass, while adb has USB_CLASS_CDC_DATA
|
||||
if (interface->bInterfaceClass == ifclass &&
|
||||
interface->bInterfaceSubClass == ifsubclass &&
|
||||
interface->bInterfaceProtocol == ifprotocol &&
|
||||
interface->bNumEndpoints == numendpoints) {
|
||||
|
||||
DBG("looking for bulk endpoints\n");
|
||||
// looks like ADB...
|
||||
ep1 = (struct usb_endpoint_descriptor *)bufptr;
|
||||
bufptr += USB_DT_ENDPOINT_SIZE;
|
||||
ep2 = (struct usb_endpoint_descriptor *)bufptr;
|
||||
bufptr += USB_DT_ENDPOINT_SIZE;
|
||||
|
||||
if (bufptr > devdesc + desclength ||
|
||||
ep1->bLength != USB_DT_ENDPOINT_SIZE ||
|
||||
ep1->bDescriptorType != USB_DT_ENDPOINT ||
|
||||
ep2->bLength != USB_DT_ENDPOINT_SIZE ||
|
||||
ep2->bDescriptorType != USB_DT_ENDPOINT) {
|
||||
DBG("endpoints not found\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// both endpoints should be bulk
|
||||
if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
|
||||
ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
|
||||
DBG("bulk endpoints not found\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// we have a match. now we just need to figure out which is in and which is out.
|
||||
if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
|
||||
local_ep_in = ep1->bEndpointAddress;
|
||||
local_ep_out = ep2->bEndpointAddress;
|
||||
} else {
|
||||
local_ep_in = ep2->bEndpointAddress;
|
||||
local_ep_out = ep1->bEndpointAddress;
|
||||
}
|
||||
|
||||
new_device(devname, local_ep_in, local_ep_out, i);
|
||||
found_device = 1;
|
||||
close(fd);
|
||||
} else {
|
||||
// skip to next interface
|
||||
bufptr += (interface->bNumEndpoints * USB_DT_ENDPOINT_SIZE);
|
||||
}
|
||||
} // end of for
|
||||
} //end of productid if
|
||||
}
|
||||
close(fd);
|
||||
} // end of if
|
||||
} // end of devdir while
|
||||
closedir(devdir);
|
||||
} //end of busdir while
|
||||
closedir(busdir);
|
||||
|
||||
return found_device;
|
||||
}
|
||||
|
||||
|
||||
static void find_devices(unsigned vendor, unsigned product1, unsigned product2)
|
||||
{
|
||||
// don't scan /proc/bus/usb if we find something in /dev/bus/usb, to avoid duplication of devices.
|
||||
if (!find_usb_devices("/dev/bus/usb", vendor, product1, product2, USB_CLASS_VENDOR_SPEC, 1, 0, 2)) {
|
||||
find_usb_devices("/proc/bus/usb", vendor, product1, product2, USB_CLASS_VENDOR_SPEC, 1, 0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_open_device(struct usb_handle *h)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
h->desc = open(h->fname, O_RDWR);
|
||||
//DBG("[ usb open %s fd = %d]\n", h->fname, h->desc);
|
||||
n = ioctl(h->desc, USBDEVFS_CLAIMINTERFACE, &h->interface);
|
||||
if(n != 0) goto fail;
|
||||
// t->usb_is_open = 1;
|
||||
return;
|
||||
|
||||
|
||||
fail:
|
||||
DBG("[ usb open %s error=%d, err_str = %s]\n",
|
||||
h->fname, errno, strerror(errno));
|
||||
if(h->desc >= 0) {
|
||||
close(h->desc);
|
||||
h->desc = -1;
|
||||
}
|
||||
// t->usb_is_open = 0;
|
||||
}
|
||||
|
||||
int usb_write(struct usb_handle *h, const void *_data, int len)
|
||||
{
|
||||
unsigned char *data = (unsigned char*) _data;
|
||||
struct usbdevfs_bulktransfer bulk;
|
||||
int n;
|
||||
|
||||
while(len >= 0) {
|
||||
int xfer = (len > 4096) ? 4096 : len;
|
||||
|
||||
bulk.ep = h->ep_out;
|
||||
bulk.len = xfer;
|
||||
bulk.data = data;
|
||||
bulk.timeout = 500 + xfer * 8;
|
||||
|
||||
bulk.timeout *= 10;
|
||||
|
||||
n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
|
||||
if(n != xfer) {
|
||||
DBG("ERROR: n = %d, errno = %d (%s)\n",
|
||||
n, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if(len == 0)
|
||||
break;
|
||||
|
||||
len -= xfer;
|
||||
data += xfer;
|
||||
if(len == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_read(struct usb_handle *h, void *_data, int len)
|
||||
{
|
||||
unsigned char *data_start = (unsigned char*) _data;
|
||||
unsigned char *data = (unsigned char*) _data;
|
||||
struct usbdevfs_bulktransfer bulk;
|
||||
int n;
|
||||
|
||||
while(len > 0) {
|
||||
int xfer = (len > 4096) ? 4096 : len;
|
||||
|
||||
bulk.ep = h->ep_in;
|
||||
bulk.len = xfer;
|
||||
bulk.data = data;
|
||||
|
||||
// adjust timeout based on the data we're transferring,
|
||||
// otherwise the timeout interrupts us partway through
|
||||
// and we get out of sync...
|
||||
bulk.timeout = 500 + xfer * 8;
|
||||
|
||||
bulk.timeout = 500 + xfer / 128;
|
||||
|
||||
// bulk.timeout *= 10;
|
||||
DBG1("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
|
||||
n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
|
||||
DBG1("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
|
||||
if(n < 0) {
|
||||
if((errno == ETIMEDOUT) && (h->desc != -1)) {
|
||||
DBG("[ timeout ]\n");
|
||||
if(n > 0){
|
||||
data += n;
|
||||
len -= n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
DBG1("ERROR: n = %d, errno = %d (%s)\n",
|
||||
n, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len -= n;
|
||||
data += n;
|
||||
if(n != xfer)
|
||||
break;
|
||||
}
|
||||
|
||||
return data - data_start;
|
||||
}
|
||||
|
||||
void usb_kick(struct usb_handle *h)
|
||||
{
|
||||
close(h->desc);
|
||||
h->desc = -1;
|
||||
}
|
||||
|
||||
int usb_close(struct usb_handle *h)
|
||||
{
|
||||
close(h->desc);
|
||||
h->desc = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void list_devices()
|
||||
{
|
||||
int i = 0;
|
||||
struct usb_handle *h = g_first_usb_device;
|
||||
while(h) {
|
||||
printf("%d: %s\n", i, h->fname);
|
||||
i++;
|
||||
h = h->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buffer[4096/*-64*/];
|
||||
int len;
|
||||
int c;
|
||||
char *arg;
|
||||
int device_index = 0;
|
||||
struct usb_handle *h;
|
||||
int i;
|
||||
|
||||
find_devices(VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER, PRODUCT_ID_SOONER_COMP);
|
||||
while(1) {
|
||||
c = getopt(argc, argv, "d:l");
|
||||
if (c == EOF)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'd':
|
||||
device_index = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'l':
|
||||
list_devices();
|
||||
return 0;
|
||||
case '?':
|
||||
fprintf(stderr, "%s: invalid option -%c\n",
|
||||
argv[0], optopt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind - 1;
|
||||
argv += optind - 1;
|
||||
|
||||
h = g_first_usb_device;
|
||||
i = device_index;
|
||||
while(i-- > 0 && h) {
|
||||
h = h->next;
|
||||
}
|
||||
if(h == NULL) {
|
||||
fprintf(stderr, "no device %d\n", device_index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
usb_open_device(h);
|
||||
if(g_first_usb_device->desc < 0) {
|
||||
fprintf(stderr, "could not open device (%s), %s\n", h->fname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
len = 0;
|
||||
if(argc == 1) {
|
||||
char *line = NULL;
|
||||
size_t line_size = 0;
|
||||
while((len = getline(&line, &line_size, stdin)) >= 0) {
|
||||
//if(len > 0 && line[len - 1] == '\n')
|
||||
// len--;
|
||||
usb_write(h, line, len);
|
||||
while(1) {
|
||||
len = usb_read(h, buffer, sizeof(buffer));
|
||||
if(len < 0)
|
||||
break;
|
||||
write(STDOUT_FILENO, buffer, len);
|
||||
if(len < (int)sizeof(buffer))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
while(argc > 1) {
|
||||
argc--;
|
||||
argv++;
|
||||
arg = *argv;
|
||||
while(arg) {
|
||||
if(*arg)
|
||||
buffer[len++] = *arg++;
|
||||
else {
|
||||
arg = NULL;
|
||||
if(argc > 1)
|
||||
buffer[len++] = ' ';
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(len == sizeof(buffer)) {
|
||||
usb_write(h, buffer, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
usb_write(h, buffer, len);
|
||||
while(1) {
|
||||
len = usb_read(h, buffer, sizeof(buffer));
|
||||
if(len < 0)
|
||||
break;
|
||||
write(STDOUT_FILENO, buffer, len);
|
||||
if(len < (int)sizeof(buffer))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -345,10 +345,7 @@ asocket* host_service_to_socket(const char* name, const char *serial)
|
|||
|
||||
name += strlen("wait-for-");
|
||||
|
||||
if (!strncmp(name, "bootloader", strlen("bootloader"))) {
|
||||
sinfo->transport = kTransportUsb;
|
||||
sinfo->state = CS_BOOTLOADER;
|
||||
} else if (!strncmp(name, "local", strlen("local"))) {
|
||||
if (!strncmp(name, "local", strlen("local"))) {
|
||||
sinfo->transport = kTransportLocal;
|
||||
sinfo->state = CS_DEVICE;
|
||||
} else if (!strncmp(name, "usb", strlen("usb"))) {
|
||||
|
|
|
@ -247,6 +247,11 @@
|
|||
*/
|
||||
#define ARCH_ARM
|
||||
|
||||
/*
|
||||
* Define if the size of enums is as short as possible,
|
||||
*/
|
||||
/* #define HAVE_SHORT_ENUMS */
|
||||
|
||||
/*
|
||||
* sprintf() format string for shared library naming.
|
||||
*/
|
||||
|
|
|
@ -122,6 +122,7 @@ static struct perms_ devperms[] = {
|
|||
{ "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },
|
||||
{ "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },
|
||||
{ "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },
|
||||
{ "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 },
|
||||
{ "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },
|
||||
{ "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 },
|
||||
{ "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
|
||||
|
|
157
init/init.c
157
init/init.c
|
@ -37,6 +37,7 @@
|
|||
#include <cutils/sockets.h>
|
||||
#include <termios.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/keychord.h>
|
||||
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
|
@ -60,6 +61,9 @@ static char bootloader[32];
|
|||
static char hardware[32];
|
||||
static unsigned revision = 0;
|
||||
static char qemu[32];
|
||||
static struct input_keychord *keychords = 0;
|
||||
static int keychords_count = 0;
|
||||
static int keychords_length = 0;
|
||||
|
||||
static void drain_action_queue(void);
|
||||
|
||||
|
@ -233,7 +237,7 @@ void service_start(struct service *svc)
|
|||
|
||||
setpgid(0, getpid());
|
||||
|
||||
/* as requested, set our gid, supplemental gids, and uid */
|
||||
/* as requested, set our gid, supplemental gids, and uid */
|
||||
if (svc->gid) {
|
||||
setgid(svc->gid);
|
||||
}
|
||||
|
@ -660,17 +664,101 @@ void open_devnull_stdio(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
void add_service_keycodes(struct service *svc)
|
||||
{
|
||||
struct input_keychord *keychord;
|
||||
int i, size;
|
||||
|
||||
if (svc->keycodes) {
|
||||
/* add a new keychord to the list */
|
||||
size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
|
||||
keychords = realloc(keychords, keychords_length + size);
|
||||
if (!keychords) {
|
||||
ERROR("could not allocate keychords\n");
|
||||
keychords_length = 0;
|
||||
keychords_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
keychord = (struct input_keychord *)((char *)keychords + keychords_length);
|
||||
keychord->version = KEYCHORD_VERSION;
|
||||
keychord->id = keychords_count + 1;
|
||||
keychord->count = svc->nkeycodes;
|
||||
svc->keychord_id = keychord->id;
|
||||
|
||||
for (i = 0; i < svc->nkeycodes; i++) {
|
||||
keychord->keycodes[i] = svc->keycodes[i];
|
||||
}
|
||||
keychords_count++;
|
||||
keychords_length += size;
|
||||
}
|
||||
}
|
||||
|
||||
int open_keychord()
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
service_for_each(add_service_keycodes);
|
||||
|
||||
/* nothing to do if no services require keychords */
|
||||
if (!keychords)
|
||||
return -1;
|
||||
|
||||
fd = open("/dev/keychord", O_RDWR);
|
||||
if (fd < 0) {
|
||||
ERROR("could not open /dev/keychord\n");
|
||||
return fd;
|
||||
}
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
ret = write(fd, keychords, keychords_length);
|
||||
if (ret != keychords_length) {
|
||||
ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
free(keychords);
|
||||
keychords = 0;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void handle_keychord(int fd)
|
||||
{
|
||||
struct service *svc;
|
||||
int ret;
|
||||
__u16 id;
|
||||
|
||||
ret = read(fd, &id, sizeof(id));
|
||||
if (ret != sizeof(id)) {
|
||||
ERROR("could not read keychord id\n");
|
||||
return;
|
||||
}
|
||||
|
||||
svc = service_find_by_keychord(id);
|
||||
if (svc) {
|
||||
INFO("starting service %s from keychord\n", svc->name);
|
||||
service_start(svc);
|
||||
} else {
|
||||
ERROR("service for keychord %d not found\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int device_fd = -1;
|
||||
int property_set_fd = -1;
|
||||
int signal_recv_fd = -1;
|
||||
int keychord_fd = -1;
|
||||
int fd_count;
|
||||
int s[2];
|
||||
int fd;
|
||||
struct sigaction act;
|
||||
char tmp[PROP_VALUE_MAX];
|
||||
struct pollfd ufds[4];
|
||||
char *tmpdev;
|
||||
char* debuggable;
|
||||
|
||||
act.sa_handler = sigchld_handler;
|
||||
act.sa_flags = SA_NOCLDSTOP;
|
||||
|
@ -723,6 +811,12 @@ int main(int argc, char **argv)
|
|||
device_fd = device_init();
|
||||
|
||||
property_init();
|
||||
|
||||
// only listen for keychords if ro.debuggable is true
|
||||
debuggable = property_get("ro.debuggable");
|
||||
if (debuggable && !strcmp(debuggable, "1")) {
|
||||
keychord_fd = open_keychord();
|
||||
}
|
||||
|
||||
if (console[0]) {
|
||||
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
|
||||
|
@ -735,27 +829,27 @@ int main(int argc, char **argv)
|
|||
close(fd);
|
||||
|
||||
if( load_565rle_image(INIT_IMAGE_FILE) ) {
|
||||
fd = open("/dev/tty0", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
const char *msg;
|
||||
fd = open("/dev/tty0", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
const char *msg;
|
||||
msg = "\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n" // console is 40 cols x 30 lines
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" A N D R O I D ";
|
||||
write(fd, msg, strlen(msg));
|
||||
close(fd);
|
||||
}
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n" // console is 40 cols x 30 lines
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" A N D R O I D ";
|
||||
write(fd, msg, strlen(msg));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (qemu[0])
|
||||
|
@ -825,6 +919,16 @@ int main(int argc, char **argv)
|
|||
ufds[1].events = POLLIN;
|
||||
ufds[2].fd = signal_recv_fd;
|
||||
ufds[2].events = POLLIN;
|
||||
fd_count = 3;
|
||||
|
||||
if (keychord_fd > 0) {
|
||||
ufds[3].fd = keychord_fd;
|
||||
ufds[3].events = POLLIN;
|
||||
fd_count++;
|
||||
} else {
|
||||
ufds[3].events = 0;
|
||||
ufds[3].revents = 0;
|
||||
}
|
||||
|
||||
#if BOOTCHART
|
||||
bootchart_count = bootchart_init();
|
||||
|
@ -838,11 +942,10 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
for(;;) {
|
||||
int nr, timeout = -1;
|
||||
int nr, i, timeout = -1;
|
||||
|
||||
ufds[0].revents = 0;
|
||||
ufds[1].revents = 0;
|
||||
ufds[2].revents = 0;
|
||||
for (i = 0; i < fd_count; i++)
|
||||
ufds[i].revents = 0;
|
||||
|
||||
drain_action_queue();
|
||||
restart_processes();
|
||||
|
@ -863,7 +966,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
nr = poll(ufds, 3, timeout);
|
||||
nr = poll(ufds, fd_count, timeout);
|
||||
if (nr <= 0)
|
||||
continue;
|
||||
|
||||
|
@ -880,6 +983,8 @@ int main(int argc, char **argv)
|
|||
|
||||
if (ufds[1].revents == POLLIN)
|
||||
handle_property_set_fd(property_set_fd);
|
||||
if (ufds[3].revents == POLLIN)
|
||||
handle_keychord(keychord_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -139,12 +139,19 @@ struct service {
|
|||
int nargs;
|
||||
char *args[1];
|
||||
struct action onrestart; /* Actions to execute on restart. */
|
||||
|
||||
/* keycodes for triggering this service via /dev/keychord */
|
||||
int *keycodes;
|
||||
int nkeycodes;
|
||||
int keychord_id;
|
||||
};
|
||||
|
||||
int parse_config_file(const char *fn);
|
||||
|
||||
struct service *service_find_by_name(const char *name);
|
||||
struct service *service_find_by_pid(pid_t pid);
|
||||
struct service *service_find_by_keychord(int keychord_id);
|
||||
void service_for_each(void (*func)(struct service *svc));
|
||||
void service_for_each_class(const char *classname,
|
||||
void (*func)(struct service *svc));
|
||||
void service_for_each_flags(unsigned matchflags,
|
||||
|
|
|
@ -45,6 +45,7 @@ enum {
|
|||
KEYWORD(ifup, COMMAND, 1, do_ifup)
|
||||
KEYWORD(insmod, COMMAND, 1, do_insmod)
|
||||
KEYWORD(import, COMMAND, 1, do_import)
|
||||
KEYWORD(keycodes, OPTION, 0, 0)
|
||||
KEYWORD(mkdir, COMMAND, 1, do_mkdir)
|
||||
KEYWORD(mount, COMMAND, 3, do_mount)
|
||||
KEYWORD(on, SECTION, 0, 0)
|
||||
|
|
|
@ -158,6 +158,9 @@ int lookup_keyword(const char *s)
|
|||
if (!strcmp(s, "nsmod")) return K_insmod;
|
||||
if (!strcmp(s, "mport")) return K_import;
|
||||
break;
|
||||
case 'k':
|
||||
if (!strcmp(s, "eycodes")) return K_keycodes;
|
||||
break;
|
||||
case 'l':
|
||||
if (!strcmp(s, "oglevel")) return K_loglevel;
|
||||
break;
|
||||
|
@ -183,7 +186,7 @@ int lookup_keyword(const char *s)
|
|||
if (!strcmp(s, "tart")) return K_start;
|
||||
if (!strcmp(s, "top")) return K_stop;
|
||||
if (!strcmp(s, "ymlink")) return K_symlink;
|
||||
if (!strcmp(s, "ysclktz")) return K_sysclktz;
|
||||
if (!strcmp(s, "ysclktz")) return K_sysclktz;
|
||||
break;
|
||||
case 't':
|
||||
if (!strcmp(s, "rigger")) return K_trigger;
|
||||
|
@ -440,6 +443,29 @@ struct service *service_find_by_pid(pid_t pid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct service *service_find_by_keychord(int keychord_id)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct service *svc;
|
||||
list_for_each(node, &service_list) {
|
||||
svc = node_to_item(node, struct service, slist);
|
||||
if (svc->keychord_id == keychord_id) {
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void service_for_each(void (*func)(struct service *svc))
|
||||
{
|
||||
struct listnode *node;
|
||||
struct service *svc;
|
||||
list_for_each(node, &service_list) {
|
||||
svc = node_to_item(node, struct service, slist);
|
||||
func(svc);
|
||||
}
|
||||
}
|
||||
|
||||
void service_for_each_class(const char *classname,
|
||||
void (*func)(struct service *svc))
|
||||
{
|
||||
|
@ -586,7 +612,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
|
|||
{
|
||||
struct service *svc = state->context;
|
||||
struct command *cmd;
|
||||
int kw, kw_nargs;
|
||||
int i, kw, kw_nargs;
|
||||
|
||||
if (nargs == 0) {
|
||||
return;
|
||||
|
@ -624,6 +650,21 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
|
|||
svc->nr_supp_gids = n - 2;
|
||||
}
|
||||
break;
|
||||
case K_keycodes:
|
||||
if (nargs < 2) {
|
||||
parse_error(state, "keycodes option requires atleast one keycode\n");
|
||||
} else {
|
||||
svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
|
||||
if (!svc->keycodes) {
|
||||
parse_error(state, "could not allocate keycodes\n");
|
||||
} else {
|
||||
svc->nkeycodes = nargs - 1;
|
||||
for (i = 1; i < nargs; i++) {
|
||||
svc->keycodes[i - 1] = atoi(args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case K_oneshot:
|
||||
svc->flags |= SVC_ONESHOT;
|
||||
break;
|
||||
|
|
|
@ -35,13 +35,15 @@
|
|||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/loop.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <cutils/misc.h>
|
||||
|
||||
#include "ASEC.h"
|
||||
#include "dm-ioctl.h"
|
||||
|
||||
//#define MODULE_FAILURE_IS_FATAL
|
||||
|
||||
extern int init_module(void *, unsigned long, const char *);
|
||||
extern int delete_module(const char *, unsigned int);
|
||||
|
@ -104,14 +106,12 @@ void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
|
|||
{
|
||||
struct asec_context *ctx;
|
||||
|
||||
if (!AsecIsEnabled())
|
||||
return NULL;
|
||||
|
||||
LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
|
||||
Name, SrcPath, BackingFile, Size, DstPath, Crypt);
|
||||
|
||||
if (!AsecIsEnabled()) {
|
||||
LOG_ERROR("AsecInit(): Disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
|
||||
LOG_ERROR("AsecInit(): Invalid arguments\n");
|
||||
return NULL;
|
||||
|
@ -159,7 +159,7 @@ static int AsecLoadModules()
|
|||
sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
|
||||
module = load_file(moduleFile, &size);
|
||||
if (!module) {
|
||||
LOG_ERROR("Failed to load module %s\n", moduleFile);
|
||||
LOG_ERROR("Failed to load module %s (%d)\n", moduleFile, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -659,8 +659,10 @@ int AsecStart(void *Handle)
|
|||
|
||||
if ((rc = AsecLoadModules()) < 0) {
|
||||
LOG_ERROR("AsecStart: Failed to load kernel modules\n");
|
||||
#ifdef MODULE_FAILURE_IS_FATAL
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((rc = AsecLoadGenerateKey(ctx))) {
|
||||
|
@ -759,8 +761,10 @@ int AsecStop(void *Handle)
|
|||
LOG_ASEC("AsecStop: Kernel modules still in use\n");
|
||||
} else {
|
||||
LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
|
||||
#ifdef MODULE_FAILURE_IS_FATAL
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ LOCAL_SRC_FILES:= \
|
|||
ProcessKiller.c \
|
||||
Server.c \
|
||||
mountd.c \
|
||||
ASEC.c
|
||||
ASEC.c \
|
||||
logwrapper.c
|
||||
|
||||
LOCAL_MODULE:= mountd
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ boolean gMassStorageConnected = false;
|
|||
static pthread_t sAutoMountThread = 0;
|
||||
static pid_t gExcludedPids[2] = {-1, -1};
|
||||
|
||||
static const char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
|
||||
static const char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
|
||||
|
||||
// number of mount points that have timeouts pending
|
||||
static int sRetriesPending = 0;
|
||||
|
@ -209,40 +209,32 @@ static int CheckFilesystem(const char *device)
|
|||
|
||||
int result = access(FSCK_MSDOS_PATH, X_OK);
|
||||
if (result != 0) {
|
||||
LOG_MOUNT("CheckFilesystem(%s): fsck_msdos not found (skipping checks)\n", device);
|
||||
LOG_MOUNT("CheckFilesystem(%s): %s not found (skipping checks)\n", FSCK_MSDOS_PATH, device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(cmdline, "%s -p %s", FSCK_MSDOS_PATH, device);
|
||||
LOG_MOUNT("Checking filesystem (%s)\n", cmdline);
|
||||
char *args[7];
|
||||
args[0] = FSCK_MSDOS_PATH;
|
||||
args[1] = "-v";
|
||||
args[2] = "-V";
|
||||
args[3] = "-w";
|
||||
args[4] = "-p";
|
||||
args[5] = device;
|
||||
args[6] = NULL;
|
||||
|
||||
// XXX: Notify framework we're disk checking
|
||||
|
||||
// XXX: PROTECT FROM VIKING KILLER
|
||||
if ((rc = system(cmdline)) < 0) {
|
||||
LOG_ERROR("Error executing disk check command (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rc = WEXITSTATUS(rc);
|
||||
LOG_MOUNT("Checking filesystem on %s\n", device);
|
||||
rc = logwrap(6, args);
|
||||
|
||||
// XXX: We need to be able to distinguish between a FS with an error
|
||||
// and a block device which does not have a FAT fs at all on it
|
||||
if (rc == 0) {
|
||||
LOG_MOUNT("Filesystem check completed OK\n");
|
||||
return 0;
|
||||
} else if (rc == 1) {
|
||||
LOG_MOUNT("Filesystem check failed (invalid usage)\n");
|
||||
LOG_MOUNT("Filesystem check failed (general failure)\n");
|
||||
return -EINVAL;
|
||||
} else if (rc == 2) {
|
||||
LOG_MOUNT("Filesystem check failed (unresolved issues)\n");
|
||||
return -EIO;
|
||||
} else if (rc == 4) {
|
||||
LOG_MOUNT("Filesystem check failed (root changed)\n");
|
||||
return -EIO;
|
||||
} else if (rc == 8) {
|
||||
LOG_MOUNT("Filesystem check failed (general failure)\n");
|
||||
return -EIO;
|
||||
} else if (rc == 12) {
|
||||
LOG_MOUNT("Filesystem check failed (exit signaled)\n");
|
||||
LOG_MOUNT("Filesystem check failed (invalid usage)\n");
|
||||
return -EIO;
|
||||
} else {
|
||||
LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
|
||||
|
@ -252,7 +244,7 @@ static int CheckFilesystem(const char *device)
|
|||
|
||||
static int DoMountDevice(const char* device, const char* mountPoint)
|
||||
{
|
||||
LOG_MOUNT("mounting %s at %s\n", device, mountPoint);
|
||||
LOG_MOUNT("Attempting mount of %s on %s\n", device, mountPoint);
|
||||
|
||||
#if CREATE_MOUNT_POINTS
|
||||
// make sure mount point exists
|
||||
|
@ -292,8 +284,10 @@ static int DoMountDevice(const char* device, const char* mountPoint)
|
|||
}
|
||||
|
||||
int result = access(device, R_OK);
|
||||
if (result != 0)
|
||||
return result;
|
||||
if (result) {
|
||||
LOG_ERROR("Unable to access '%s' (%d)\n", device, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if ((result = CheckFilesystem(device))) {
|
||||
LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
|
||||
|
@ -304,7 +298,6 @@ static int DoMountDevice(const char* device, const char* mountPoint)
|
|||
// - SD cards with bad filesystem
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Extra safety measures:
|
||||
flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
|
||||
|
@ -319,9 +312,9 @@ static int DoMountDevice(const char* device, const char* mountPoint)
|
|||
result = mount(device, mountPoint, "vfat", flags,
|
||||
"utf8,uid=1000,gid=1000,fmask=711,dmask=700");
|
||||
}
|
||||
LOG_MOUNT("mount returned %d errno: %d\n", result, errno);
|
||||
|
||||
if (result == 0) {
|
||||
LOG_MOUNT("Partition %s mounted on %s\n", device, mountPoint);
|
||||
NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
|
||||
|
||||
MountPoint* mp = sMountPointList;
|
||||
|
@ -342,13 +335,13 @@ static int DoMountDevice(const char* device, const char* mountPoint)
|
|||
mp = mp -> next;
|
||||
}
|
||||
} else if (errno == EBUSY) {
|
||||
// ignore EBUSY, since it usually means the device is already mounted
|
||||
LOG_MOUNT("Mount failed (already mounted)\n");
|
||||
result = 0;
|
||||
} else {
|
||||
#if CREATE_MOUNT_POINTS
|
||||
rmdir(mountPoint);
|
||||
#endif
|
||||
LOG_MOUNT("mount failed, errno: %d\n", errno);
|
||||
LOG_MOUNT("Unable to mount %s on %s\n", device, mountPoint);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -404,8 +397,11 @@ static int MountPartition(const char* device, const char* mountPoint)
|
|||
// attempt to mount subpartitions of the device
|
||||
for (i = 1; i < 10; i++)
|
||||
{
|
||||
int rc;
|
||||
snprintf(buf, sizeof(buf), "%sp%d", device, i);
|
||||
if (DoMountDevice(buf, mountPoint) == 0)
|
||||
rc = DoMountDevice(buf, mountPoint);
|
||||
LOG_MOUNT("DoMountDevice(%s, %s) = %d\n", buf, mountPoint, rc);
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,304 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_DM_IOCTL_V4_H
|
||||
#define _LINUX_DM_IOCTL_V4_H
|
||||
|
||||
#ifdef linux
|
||||
# include <linux/types.h>
|
||||
#endif
|
||||
|
||||
#define DM_DIR "mapper" /* Slashes not supported */
|
||||
#define DM_MAX_TYPE_NAME 16
|
||||
#define DM_NAME_LEN 128
|
||||
#define DM_UUID_LEN 129
|
||||
|
||||
/*
|
||||
* A traditional ioctl interface for the device mapper.
|
||||
*
|
||||
* Each device can have two tables associated with it, an
|
||||
* 'active' table which is the one currently used by io passing
|
||||
* through the device, and an 'inactive' one which is a table
|
||||
* that is being prepared as a replacement for the 'active' one.
|
||||
*
|
||||
* DM_VERSION:
|
||||
* Just get the version information for the ioctl interface.
|
||||
*
|
||||
* DM_REMOVE_ALL:
|
||||
* Remove all dm devices, destroy all tables. Only really used
|
||||
* for debug.
|
||||
*
|
||||
* DM_LIST_DEVICES:
|
||||
* Get a list of all the dm device names.
|
||||
*
|
||||
* DM_DEV_CREATE:
|
||||
* Create a new device, neither the 'active' or 'inactive' table
|
||||
* slots will be filled. The device will be in suspended state
|
||||
* after creation, however any io to the device will get errored
|
||||
* since it will be out-of-bounds.
|
||||
*
|
||||
* DM_DEV_REMOVE:
|
||||
* Remove a device, destroy any tables.
|
||||
*
|
||||
* DM_DEV_RENAME:
|
||||
* Rename a device.
|
||||
*
|
||||
* DM_SUSPEND:
|
||||
* This performs both suspend and resume, depending which flag is
|
||||
* passed in.
|
||||
* Suspend: This command will not return until all pending io to
|
||||
* the device has completed. Further io will be deferred until
|
||||
* the device is resumed.
|
||||
* Resume: It is no longer an error to issue this command on an
|
||||
* unsuspended device. If a table is present in the 'inactive'
|
||||
* slot, it will be moved to the active slot, then the old table
|
||||
* from the active slot will be _destroyed_. Finally the device
|
||||
* is resumed.
|
||||
*
|
||||
* DM_DEV_STATUS:
|
||||
* Retrieves the status for the table in the 'active' slot.
|
||||
*
|
||||
* DM_DEV_WAIT:
|
||||
* Wait for a significant event to occur to the device. This
|
||||
* could either be caused by an event triggered by one of the
|
||||
* targets of the table in the 'active' slot, or a table change.
|
||||
*
|
||||
* DM_TABLE_LOAD:
|
||||
* Load a table into the 'inactive' slot for the device. The
|
||||
* device does _not_ need to be suspended prior to this command.
|
||||
*
|
||||
* DM_TABLE_CLEAR:
|
||||
* Destroy any table in the 'inactive' slot (ie. abort).
|
||||
*
|
||||
* DM_TABLE_DEPS:
|
||||
* Return a set of device dependencies for the 'active' table.
|
||||
*
|
||||
* DM_TABLE_STATUS:
|
||||
* Return the targets status for the 'active' table.
|
||||
*
|
||||
* DM_TARGET_MSG:
|
||||
* Pass a message string to the target at a specific offset of a device.
|
||||
*
|
||||
* DM_DEV_SET_GEOMETRY:
|
||||
* Set the geometry of a device by passing in a string in this format:
|
||||
*
|
||||
* "cylinders heads sectors_per_track start_sector"
|
||||
*
|
||||
* Beware that CHS geometry is nearly obsolete and only provided
|
||||
* for compatibility with dm devices that can be booted by a PC
|
||||
* BIOS. See struct hd_geometry for range limits. Also note that
|
||||
* the geometry is erased if the device size changes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All ioctl arguments consist of a single chunk of memory, with
|
||||
* this structure at the start. If a uuid is specified any
|
||||
* lookup (eg. for a DM_INFO) will be done on that, *not* the
|
||||
* name.
|
||||
*/
|
||||
struct dm_ioctl {
|
||||
/*
|
||||
* The version number is made up of three parts:
|
||||
* major - no backward or forward compatibility,
|
||||
* minor - only backwards compatible,
|
||||
* patch - both backwards and forwards compatible.
|
||||
*
|
||||
* All clients of the ioctl interface should fill in the
|
||||
* version number of the interface that they were
|
||||
* compiled with.
|
||||
*
|
||||
* All recognised ioctl commands (ie. those that don't
|
||||
* return -ENOTTY) fill out this field, even if the
|
||||
* command failed.
|
||||
*/
|
||||
uint32_t version[3]; /* in/out */
|
||||
uint32_t data_size; /* total size of data passed in
|
||||
* including this struct */
|
||||
|
||||
uint32_t data_start; /* offset to start of data
|
||||
* relative to start of this struct */
|
||||
|
||||
uint32_t target_count; /* in/out */
|
||||
int32_t open_count; /* out */
|
||||
uint32_t flags; /* in/out */
|
||||
uint32_t event_nr; /* in/out */
|
||||
uint32_t padding;
|
||||
|
||||
uint64_t dev; /* in/out */
|
||||
|
||||
char name[DM_NAME_LEN]; /* device name */
|
||||
char uuid[DM_UUID_LEN]; /* unique identifier for
|
||||
* the block device */
|
||||
char data[7]; /* padding or data */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to specify tables. These structures appear after the
|
||||
* dm_ioctl.
|
||||
*/
|
||||
struct dm_target_spec {
|
||||
uint64_t sector_start;
|
||||
uint64_t length;
|
||||
int32_t status; /* used when reading from kernel only */
|
||||
|
||||
/*
|
||||
* Location of the next dm_target_spec.
|
||||
* - When specifying targets on a DM_TABLE_LOAD command, this value is
|
||||
* the number of bytes from the start of the "current" dm_target_spec
|
||||
* to the start of the "next" dm_target_spec.
|
||||
* - When retrieving targets on a DM_TABLE_STATUS command, this value
|
||||
* is the number of bytes from the start of the first dm_target_spec
|
||||
* (that follows the dm_ioctl struct) to the start of the "next"
|
||||
* dm_target_spec.
|
||||
*/
|
||||
uint32_t next;
|
||||
|
||||
char target_type[DM_MAX_TYPE_NAME];
|
||||
|
||||
/*
|
||||
* Parameter string starts immediately after this object.
|
||||
* Be careful to add padding after string to ensure correct
|
||||
* alignment of subsequent dm_target_spec.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to retrieve the target dependencies.
|
||||
*/
|
||||
struct dm_target_deps {
|
||||
uint32_t count; /* Array size */
|
||||
uint32_t padding; /* unused */
|
||||
uint64_t dev[0]; /* out */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to get a list of all dm devices.
|
||||
*/
|
||||
struct dm_name_list {
|
||||
uint64_t dev;
|
||||
uint32_t next; /* offset to the next record from
|
||||
the _start_ of this */
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to retrieve the target versions
|
||||
*/
|
||||
struct dm_target_versions {
|
||||
uint32_t next;
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to pass message to a target
|
||||
*/
|
||||
struct dm_target_msg {
|
||||
uint64_t sector; /* Device sector */
|
||||
|
||||
char message[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* If you change this make sure you make the corresponding change
|
||||
* to dm-ioctl.c:lookup_ioctl()
|
||||
*/
|
||||
enum {
|
||||
/* Top level cmds */
|
||||
DM_VERSION_CMD = 0,
|
||||
DM_REMOVE_ALL_CMD,
|
||||
DM_LIST_DEVICES_CMD,
|
||||
|
||||
/* device level cmds */
|
||||
DM_DEV_CREATE_CMD,
|
||||
DM_DEV_REMOVE_CMD,
|
||||
DM_DEV_RENAME_CMD,
|
||||
DM_DEV_SUSPEND_CMD,
|
||||
DM_DEV_STATUS_CMD,
|
||||
DM_DEV_WAIT_CMD,
|
||||
|
||||
/* Table level cmds */
|
||||
DM_TABLE_LOAD_CMD,
|
||||
DM_TABLE_CLEAR_CMD,
|
||||
DM_TABLE_DEPS_CMD,
|
||||
DM_TABLE_STATUS_CMD,
|
||||
|
||||
/* Added later */
|
||||
DM_LIST_VERSIONS_CMD,
|
||||
DM_TARGET_MSG_CMD,
|
||||
DM_DEV_SET_GEOMETRY_CMD
|
||||
};
|
||||
|
||||
#define DM_IOCTL 0xfd
|
||||
|
||||
#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
|
||||
#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
|
||||
#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_VERSION_MAJOR 4
|
||||
#define DM_VERSION_MINOR 13
|
||||
#define DM_VERSION_PATCHLEVEL 0
|
||||
#define DM_VERSION_EXTRA "-ioctl (2007-10-18)"
|
||||
|
||||
/* Status bits */
|
||||
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
|
||||
#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */
|
||||
#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */
|
||||
|
||||
/*
|
||||
* Flag passed into ioctl STATUS command to get table information
|
||||
* rather than current status.
|
||||
*/
|
||||
#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */
|
||||
|
||||
/*
|
||||
* Flags that indicate whether a table is present in either of
|
||||
* the two table slots that a device has.
|
||||
*/
|
||||
#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */
|
||||
#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
|
||||
|
||||
/*
|
||||
* Indicates that the buffer passed in wasn't big enough for the
|
||||
* results.
|
||||
*/
|
||||
#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */
|
||||
|
||||
/*
|
||||
* This flag is now ignored.
|
||||
*/
|
||||
#define DM_SKIP_BDGET_FLAG (1 << 9) /* In */
|
||||
|
||||
/*
|
||||
* Set this to avoid attempting to freeze any filesystem when suspending.
|
||||
*/
|
||||
#define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */
|
||||
|
||||
/*
|
||||
* Set this to suspend without flushing queued ios.
|
||||
*/
|
||||
#define DM_NOFLUSH_FLAG (1 << 11) /* In */
|
||||
|
||||
#endif /* _LINUX_DM_IOCTL_H */
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "private/android_filesystem_config.h"
|
||||
#include "cutils/log.h"
|
||||
|
||||
int parent(const char *tag, int parent_read) {
|
||||
int status;
|
||||
char buffer[4096];
|
||||
|
||||
int a = 0; // start index of unprocessed data
|
||||
int b = 0; // end index of unprocessed data
|
||||
int sz;
|
||||
while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
|
||||
|
||||
sz += b;
|
||||
// Log one line at a time
|
||||
for (b = 0; b < sz; b++) {
|
||||
if (buffer[b] == '\r') {
|
||||
buffer[b] = '\0';
|
||||
} else if (buffer[b] == '\n') {
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
a = b + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (a == 0 && b == sizeof(buffer) - 1) {
|
||||
// buffer is full, flush
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
b = 0;
|
||||
} else if (a != b) {
|
||||
// Keep left-overs
|
||||
b -= a;
|
||||
memmove(buffer, &buffer[a], b);
|
||||
a = 0;
|
||||
} else {
|
||||
a = 0;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
}
|
||||
// Flush remaining data
|
||||
if (a != b) {
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
}
|
||||
status = 0xAAAA;
|
||||
if (wait(&status) != -1) { // Wait for child
|
||||
if (WIFEXITED(status)) {
|
||||
LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
|
||||
WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status))
|
||||
LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
|
||||
WTERMSIG(status));
|
||||
else if (WIFSTOPPED(status))
|
||||
LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
|
||||
WSTOPSIG(status));
|
||||
} else
|
||||
LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
|
||||
strerror(errno), errno);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
void child(int argc, char* argv[]) {
|
||||
// create null terminated argv_child array
|
||||
char* argv_child[argc + 1];
|
||||
memcpy(argv_child, argv, argc * sizeof(char *));
|
||||
argv_child[argc] = NULL;
|
||||
|
||||
// XXX: PROTECT FROM VIKING KILLER
|
||||
if (execvp(argv_child[0], argv_child)) {
|
||||
LOG(LOG_ERROR, "logwrapper",
|
||||
"executing %s failed: %s\n", argv_child[0], strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int logwrap(int argc, char* argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
int parent_ptty;
|
||||
int child_ptty;
|
||||
char *child_devname = NULL;
|
||||
|
||||
/* Use ptty instead of socketpair so that STDOUT is not buffered */
|
||||
parent_ptty = open("/dev/ptmx", O_RDWR);
|
||||
if (parent_ptty < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
|
||||
((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Failed to fork\n");
|
||||
return -errno;
|
||||
} else if (pid == 0) {
|
||||
child_ptty = open(child_devname, O_RDWR);
|
||||
if (child_ptty < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Problem with child ptty\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// redirect stdout and stderr
|
||||
close(parent_ptty);
|
||||
dup2(child_ptty, 1);
|
||||
dup2(child_ptty, 2);
|
||||
close(child_ptty);
|
||||
|
||||
child(argc, argv);
|
||||
} else {
|
||||
// switch user and group to "log"
|
||||
// this may fail if we are not root,
|
||||
// but in that case switching user/group is unnecessary
|
||||
|
||||
// setgid(AID_LOG);
|
||||
// setuid(AID_LOG);
|
||||
|
||||
return parent(argv[0], parent_ptty);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -177,6 +177,8 @@ const char *AsecMountPoint(void *Handle);
|
|||
|
||||
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
|
||||
|
||||
// logwrapper.c
|
||||
int logwrap(int argc, char* argv[]);
|
||||
|
||||
// Server.c
|
||||
|
||||
|
|
Loading…
Reference in New Issue